图片 4

如开采意气风发套设备驱动

1.C#跨平台物联网通信框架ServerSuperIO(SSIO卡塔 尔(阿拉伯语:قطر‎介绍

《物联网框架ServerSuperIO教程》-4.如开拓大器晚成套装置驱动,同有时间扶植串口和互联网通信。附:现在扶持Windows 10 IOT,win10iot

1.C#跨平台物联网通信框架ServerSuperIO(SSIO卡塔尔介绍

《连载 | 物联网框架ServerSuperIO教程》1.4种简报形式机制。

《连载 | 物联网框架ServerSuperIO教程》2.劳务实例的布署参数表达

《连载 | 物联网框架ServerSuperIO教程》- 3.设施驱动介绍

 

注:ServerSuperIO有相当大恐怕被移植到Windows 10
IOT上,那么今后有希望开采意气风发套装置驱动,能够分段在服务端、嵌入式设备中,将产生完整的消除方案。

     
今后已经调节和测量检验通过一些代码,还得需求生龙活虎段时间,日常都以晚上干,时间也许有限。如下图:

图片 1

 

目       录

4.如开采风流倜傥套装置驱动,同一时间协理串口和网络通信… 2

4.1           概述… 2

4.2           通信左券规定… 2

4.2.1    发送读实时数据命令左券… 2

4.2.2    解析实时数据左券… 3

4.2.3    发送和接纳数据事例… 3

4.3           开荒设备驱动… 3

4.3.1    营造实时数据长久对象(不是必得卡塔尔国… 3

4.3.2    构建参数数据漫长对象… 5

4.3.3    塑造发送和解析契约命令对象… 5

4.3.4    构建筑协会谈商讨驱动对象… 6

4.3.5    创设设备驱动对象… 8

4.4           营造宿主程序… 12

4.5           运维效果… 15

 

 

《连载 |
物联网框架ServerSuperIO教程》1.4种简报格局机制。

4.如开荒生机勃勃套装置驱动,同期扶持串口和互连网通信

《连载 |
物联网框架ServerSuperIO教程》2.劳务实例的安插参数表明

4.1    概述

    
作为物联网通信框架,肯定要帮忙各个通信链路,在三种通信链路的根底上做到五种简报左券的竞相,举个例子:Modbus、自定义协商等等。不过,有三个标题:针对同生龙活虎台硬件设备或传感器,完结串口和网络二种简报方式的多寡采摘和调节,是或不是要分别写代码?设若从切实角度深入分析,同风流倜傥硬件,它要成功的事体逻辑断定是平等的,所以ServerSuperIO物联网框架,允许开拓意气风发套装置驱动,同一时候援救串口和网络二种简报格局的相互。

    
通信相当轻巧、交互很简短、业务很简短……如若把数不清简短的难题合在一同,那么就变得不轻易了,所以要有三个框架性的事物,重新把多数标题变得轻巧。

《连载 | 物联网框架ServerSuperIO教程》-
3.设施驱动介绍

4.2    通信协议鲜明

   
在实现三个装置驱动的支付早先,首先要通晓它的报道合同,好比五个人调换的语言相像。针对电视发表协议,大家自定义叁个简单易行人机联作情势,只是发送命令,提取数额消息。

 

4.2.1    发送读实时数据命令左券

    
电脑发送0x61发令为读实时数据命令,共发送6个字节,校验和为从“从机地址”最早的丰裕和,不富含“数据报头”、“校验和”和“合同甘休”。

     发送指令数据帧如下:

帧结构

数码报头

从机地址

一声令下代码

校验和

情商截止

0x55

0xAA

 

0x61

 

0x0D

字节数

1

1

1

1

1

1

  

注:ServerSuperIO有比超大希望被移植到Windows
10
IOT上,那么以后有非常的大可能率开荒大器晚成套装置驱动,能够分段在服务端、嵌入式设备中,将产生全体的解决方案。

4.2.2    解析实时数据左券

   
下位机选用到读实时数据命令后,并校验成功,重临实时数据,校验和为从“从机地址”初叶的增加和,不满含“数据报头”、“校验和”和“合同结束”。

    接纳数据帧如下:

帧结构

数量报头

从机地址

指令代码

流量

信号

校验和

说道甘休

0x55

0xAA

 

0x61

浮点型

浮点型

 

0x0D

字节数

1

1

1

1

4

 

4

1

1

     
以往已经调试通过有个别代码,还得要求生龙活虎段时间,平时都以夜间干,时间也轻巧。如下图:

4.2.3    发送和接受数据事例

发送(十三进制卡塔 尔(阿拉伯语:قطر‎:0x55 0xaa 0x00 0x61 0x61 0x0d

选用(十九进制卡塔 尔(阿拉伯语:قطر‎:0x55 0xaa 0x00 0x61 0x43 0x7a 0x00 0x00 0x43 0xb4 0x15
0x0d

流量数据为:250.00

随机信号数据为:360.00

图片 2

4.3    开采设备驱动

 

4.3.1    营造实时数据长久对象(不是必得卡塔尔

1.经过重返数据的通信左券,有流量和功率信号四个动态变量,大家必要创建叁个动态目的实体类,重要用于公约驱动与器材驱动之间的多寡交互作用。代码如下:

public class Dyn
{
        private float _Flow = 0.0f;
        /// <summary>
        /// 流量
        /// </summary>
        public float Flow
        {
            get { return _Flow; }
            set { _Flow = value; }
        }
        private float _Signal = 0.0f;
        /// <summary>
        /// 信号
        /// </summary>
        public float Signal
        {
            get { return _Signal; }
            set { _Signal = value; }
        }
}

 
2.大家根本的办事是要成立多少个实时数据悠久对象类,实时缓存数据新闻,也足以把该实时数据音信保存到数据库中或其余存储媒介物。实时数码持久对象类的代码如下:

public class DeviceDyn:DeviceDynamic
{
        public DeviceDyn() : base()
        {
            Dyn=new Dyn();
        }
        public override string GetAlertState()
        {
            throw new NotImplementedException("无报警信息");
        }
        public override object Repair()
        {
            return new DeviceDyn();
        }
        public Dyn Dyn { get; set; }
}

     DeviceDyn
类世襲自DeviceDynamic,因为各种硬件设备的报告急察方音讯有相当大概率不平等,所以GetAlertState函数能够实该功用,可是SSIO框架并从未一向引用;那一个类精气神儿上是一个能够连串化,在不加互斥的情形下也许招致文件损坏,所以Repair能够变成修复功用,在DeviceDynamic基类里完结了该意义;别的,完结DeviceDynamic基类自带三个函数,Save函数用于长久化(类别化卡塔 尔(阿拉伯语:قطر‎此类的新闻,Load用于获取(反类别化卡塔 尔(英语:State of Qatar)此类的音信,在器械驱动中能够动用。

目       录

4.3.2    构建参数数据持久对象

   
平日的话硬件设备会有读参数的命令,那么重返来的参数也亟需开展长久化存款和储蓄,並且每台器具的参数都大概不等同,在那提供三个可扩展的接口。在这里个通信公约中并不曾涉及到设备参数相关的说道表达,不过大家也急需创制贰个参数数据长久对象类,能够不写任何扩张的参数属性,在SSIO框架对参数的接口进行了援用,那是必得举办了劳作。代码如下:

public class DevicePara:ServerSuperIO.Device.DeviceParameter
{
        public override object Repair()
        {
            return new DevicePara();
        }
}

    
DevicePara世襲自DeviceParameter类,景况与实时数据漫长对象相通,能够参数。

4.如开垦豆蔻梢头套设备驱动,同期帮忙串口和网络通信… 2

4.3.3    创设发送和剖判合同命令对象

   
与器械开展人机联作会涉及到广大交互作用式的吩咐或指令代码,而这一个命令在SSIO框架内是以商量命令对象的款式存在,大要包蕴四个部:施行命令接口、打包发送数据接口、解析选用数据接口等。

   
针对地方的简报公约,有一个61指令,那么我们就足以凭借61发令为命名创设贰个商议命令对象,包罗发送数据和深入分析数据部分。假诺有其余命令代码,闻一知十。代码如下:

internal class DeviceCommand:ProtocolCommand
{
        public override string Name
        {
            get { return "61"; }
        }

        public override void ExcuteCommand<T>(T t)
        {
            throw new NotImplementedException();
        }

        public override byte[] Package<T> (string code, T1 t1,T2 t2)
        {
            //发送:0x55 0xaa 0x00 0x61 0x61 0x0d
            byte[] data = new byte[6];
            data[0] = 0x55;
            data[1] = 0xaa;
            data[2] = byte.Parse(code);
            data[3] = 0x61;
            data[4] = this.ProtocolDriver.GetCheckData(data)[0];
            data[5] = 0x0d;
            return data;
        }

        public override dynamic Analysis<T>(byte[] data, T t)
        {
            Dyn dyn = new Dyn()
            //一般下位机是单片的话,接收到数据的高低位需要互换,才能正常解析。
            byte[] flow = BinaryUtil.SubBytes(data, 4, 4, true);
            dyn.Flow = BitConverter.ToSingle(flow, 0);
            byte[] signal = BinaryUtil.SubBytes(data, 8, 4, true);
            dyn.Signal = BitConverter.ToSingle(signal, 0);
            return dyn;
        }

}

    
营造筑协会议命令需求任何后续自ProtocolCommand,依据广播发表合同规定,Name属性再次回到61,作为第一字;Package是包装要送的数据新闻;Analysis对应着采取数据之后实行分析操作。就这么贰个粗略的说道命令驱动就构建完结了。

4.1           概述… 2

4.3.4    营造筑协会商驱动对象

   
有了议和命令之后,我们要求营造筑协会谈商讨驱动对象,SSIO框架扶持自定义斟酌也在于此,况且与设备驱动的接口相关联,在SSIO框架的高端应用中也开展了援引,营造那引对象很入眼。代码如下:

internal class DeviceProtocol:ProtocolDriver
{
        public override bool CheckData(byte[] data)
        {
            if (data[0] == 0x55 && data[1] == 0xaa && data[data.Length - 1] == 0x0d)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public override byte[] GetCommand(byte[] data)
        {
            return new byte[] { data[3] };
        }

        public override int GetAddress(byte[] data)
        {
            return data[2];
        }

        public override byte[] GetHead(byte[] data)
        {
            return new byte[] { data[0], data[1] };
        }

        public override byte[] GetEnd(byte[] data)
        {
            return new byte[] { data[data.Length - 1] };
        }

        public override byte[] GetCheckData(byte[] data)
        {
            byte checkSum = 0;
            for (int i = 2; i < data.Length - 2; i++)
            {
                checkSum += data[i];
            }
            return new byte[] { checkSum };
        }

        public override string GetCode(byte[] data)
        {
            throw new NotImplementedException();
        }

        public override int GetPackageLength(byte[] data, IChannel channel, ref int readTimeout)
        {
           throw new NotImplementedException();
        }
}

     DeviceProtocol 公约驱动世襲自ProtocolDriver
,一个装置驱动只存在二个商量驱动,一个公约驱动能够存在三个商量命令(如61发令卡塔尔国。该类中的CheckData函数超级重视,SSIO框架中的设备驱动基类援引了,主假如瓜熟蒂落校验接受数据的完事性,是或不是符合合同,从而决定了通信状态:通信寻常、通信中断、通信苦恼、甚至通信未知,差异的简报状态也调整了调用设备驱动中的哪个函数接口:Communicate、CommunicateInterrupt、CommunicateError和CommunicateNone。

4.2           通信公约明确… 2

4.3.5    创设设备驱动对象

    
上边包车型客车根底专业都做完未来,将来就营造设备驱动的中坚部分,相当于SSIO框架与设施驱动对接、和煦、调治的唯后生可畏接口,写完这几个接口,设备驱动就足以在SSIO上直接运维了,而且与硬件装置开展相互影响。直接上代码:

public class DeviceDriver:RunDevice
{
        private DeviceDyn _deviceDyn;
        private DevicePara _devicePara;
        private DeviceProtocol _protocol;
        public DeviceDriver() : base()
        {
            _devicePara = new DevicePara();
            _deviceDyn = new DeviceDyn();
            _protocol = new DeviceProtocol();
        }

        public override void Initialize(string devid)
        {
            this.Protocol.InitDriver(this.GetType(),null);
            //初始化设备参数信息
            _devicePara.DeviceID = devid;//设备的ID必须先赋值,因为要查找对应的参数文件。
            if (System.IO.File.Exists(_devicePara.SavePath))
            {
                //如果参数文件存在,则获得参数实例
                _devicePara = _devicePara.Load<DevicePara>();
            }
            else
            {
                //如果参数文件不存在,则序列化一个文件
                _devicePara.Save<DevicePara>(_devicePara);
            }

            //初始化设备实时数据信息
            _deviceDyn.DeviceID = devid;//设备的ID必须先赋值,因为要查找对应的实时数据文件。
            if (System.IO.File.Exists(_deviceDyn.SavePath))
            {
                //参数文件存在,则获得参数实例
                _deviceDyn = _deviceDyn.Load<DeviceDyn>();
            }
            else
            {
                //如果参数文件不存在,则序列化一个文件
                _deviceDyn.Save<DeviceDyn>(_deviceDyn);
            }
        }

        public override byte[] GetConstantCommand()
        {
            return this.Protocol.DriverPackage<String>("0", "61", null);
        }

        public override void Communicate(ServerSuperIO.Communicate.IRequestInfo info)
        {
            Dyn dyn = this.Protocol.DriverAnalysis<String>("61", info.Data, null);
            if (dyn != null)
            {
                _deviceDyn.Dyn = dyn;
            }
            OnDeviceRuningLog("通讯正常");
        }

        public override void CommunicateInterrupt(ServerSuperIO.Communicate.IRequestInfo info)
        {
            OnDeviceRuningLog("通讯中断");
        }

        public override void CommunicateError(ServerSuperIO.Communicate.IRequestInfo info)
        {
            OnDeviceRuningLog("通讯干扰");
        }

        public override void CommunicateNone()
        {
            OnDeviceRuningLog("通讯未知");
        }

        public override void Alert()
        {
            return;
        }

        public override void Save()
        {
            try
            {
                _deviceDyn.Save<DeviceDyn>(_deviceDyn);
            }
            catch (Exception ex)
            {
                OnDeviceRuningLog(ex.Message);
            }
        }

        public override void Show()
        {
            List<string> list=new List<string>();
            list.Add(_devicePara.DeviceName);
            list.Add(_deviceDyn.Dyn.Flow.ToString());
            list.Add(_deviceDyn.Dyn.Signal.ToString());
            OnDeviceObjectChanged(list.ToArray());
        }

        public override void UnknownIO()
        {
            OnDeviceRuningLog("未知通讯接口");
        }

        public override void CommunicateStateChanged(ServerSuperIO.Communicate.CommunicateState comState)
        {
            OnDeviceRuningLog("通讯状态改变");
        }

        public override void ChannelStateChanged(ServerSuperIO.Communicate.ChannelState channelState)
        {
            OnDeviceRuningLog("通道状态改变");
        }

        public override void Exit()
        {
            OnDeviceRuningLog("退出设备");
        }

        public override void Delete()
        {
            OnDeviceRuningLog("删除设备");
        }

        public override object GetObject()
        {
            throw new NotImplementedException();
        }

        public override void ShowContextMenu()
        {
            throw new NotImplementedException();
        }

        public override IDeviceDynamic DeviceDynamic
        {
            get { return _deviceDyn; }
        }

        public override IDeviceParameter DeviceParameter
        {
            get { return _devicePara; }
        }

        public override IProtocolDriver Protocol
       {
            get { return _protocol;}
        }

        public override DeviceType DeviceType
        {
            get { return DeviceType.Common; }
        }

        public override string ModelNumber
        {
            get { return "serversuperio"; }
        }

        public override System.Windows.Forms.Control DeviceGraphics
        {
            get { throw new NotImplementedException(); }
        }
}

   
实时动态数据对象_deviceDyn、参数数据对象_devicePara、合同驱动对象_protocol分别提须求接口:DeviceDynamic、DeviceParameter和Protocol,为SSIO提供可引用的功底属性参数。

    
Initialize是设备驱动先导化的函数接口,在这些接口实现七个基本点办事:开端化合同驱动和参数性的音信。通过this.Protocol.InitDriver(this.GetType(),null);代码可以加载全体协议命令到和睦驱动的缓存中,以便实时调用。当然这里边也能够拓宽别之处的办事,然而注意对分外的拍卖。

    
DeviceType那么些是器具的种类,日常钦定为Common就好了。别的函数接口功用已经在《物联网框架ServerSuperIO教程-3.设备驱动介绍》中详细介绍了,请参见。

4.2.1    发送读实时数据命令左券… 2

4.4    营造宿主程序

    
二个简短的配备驱动就曾经开荒好了,光有驱动还充足,那么大家依据SSIO框架再写几行代码,完结一个宿主程序,把道具驱动实例化,放SSIO的劳务实例中运转,落成串口和网络三种方式的报纸发表交互作用,代码也极度轻便。代码如下:

class Program
{
        static void Main(string[] args)
        {
            DeviceDriver dev1 = new DeviceDriver();
            dev1.DeviceParameter.DeviceName = "串口设备1";
            dev1.DeviceParameter.DeviceAddr = 0;
            dev1.DeviceParameter.DeviceID = "0";
            dev1.DeviceDynamic.DeviceID = "0";
            dev1.DeviceParameter.COM.Port = 1;
            dev1.DeviceParameter.COM.Baud = 9600;
            dev1.CommunicateType = CommunicateType.COM;
            dev1.Initialize("0");

            DeviceDriver dev4 = new DeviceDriver();
            dev4.DeviceParameter.DeviceName = "网络设备2";
            dev4.DeviceParameter.DeviceAddr = 0;
            dev4.DeviceParameter.DeviceID = "3";
            dev4.DeviceDynamic.DeviceID = "3";
            dev4.DeviceParameter.NET.RemoteIP = "127.0.0.1";
            dev4.DeviceParameter.NET.RemotePort = 9600;
            dev4.CommunicateType = CommunicateType.NET;
            dev4.Initialize("3");

            IServer server = new ServerFactory().CreateServer(new ServerConfig()
            {
                ServerName = "服务实例1",
                SocketMode = SocketMode.Tcp,
                ControlMode = ControlMode.Loop,
                CheckSameSocketSession = false,
                StartCheckPackageLength = false,
            });

            server.AddDeviceCompleted += server_AddDeviceCompleted;
            server.DeleteDeviceCompleted += server_DeleteDeviceCompleted;
            server.SocketConnected+=server_SocketConnected;
            server.SocketClosed+=server_SocketClosed;
            server.Start();

            server.AddDevice(dev1);
            server.AddDevice(dev4);

            while ("exit"==Console.ReadLine())
            {
                 server.Stop();
            }
        }

        private static void server_SocketClosed(string ip, int port)
        {
            Console.WriteLine(String.Format("断开:{0}-{1} 成功", ip, port));
        }

        private static void server_SocketConnected(string ip, int port)
        {
            Console.WriteLine(String.Format("连接:{0}-{1} 成功",ip, port));
        }

        private static void server_AddDeviceCompleted(string devid, string devName, bool isSuccess)

        {
            Console.WriteLine(devName+",增加:"+isSuccess.ToString());
        }

        private static void server_DeleteDeviceCompleted(string devid, string devName, bool isSuccess)
        {
            Console.WriteLine(devName + ",删除:" + isSuccess.ToString());
        }
    }
}

    
那一个代码大家都能看精通,具体的主宰格局我们接下去会相继介绍。在构建宿主程序的时候,切忌对劳动实例那样引用:server.ChannelManager、server.ControllerManager、server.DeviceManager。即使提供了那样的接口,首假如为着SSIO框架之中接纳的,无需大家单独去操作那一个接口。有的网上朋友是如此的写的,那么就改为了叁个纯的通讯IO框架,那么就失去了SSIO框架本人的价值。作为二遍开垦者,只需求设置设备驱动的参数,以至向劳动实例中追加或删除设备就行了,其余兼具的周转总体交付SSIO框架来完毕。

4.2.2    剖判实时数据公约… 3

4.5    运维效果

 图片 3

 

1.[连载]《C#通信(串口和网络卡塔 尔(英语:State of Qatar)框架的宏图与落实》

2.[开源]C#跨平台物联网通信框架ServerSuperIO(SSIO卡塔尔国介绍

2.使用SuperIO(SIO卡塔尔和开源跨平台物联网框架ServerSuperIO(SSIO卡塔尔营造系统的欧洲经济共同体方案

3.C#工业物联网和集成系统应用方案的手艺路线(数据源、数据搜罗、数据上传与摄取、ActiveMQ、Mongodb、WebApi、手提式有线电话机App卡塔 尔(阿拉伯语:قطر‎

5.ServerSuperIO开源地址:

物联网&集成本领(.NET) QQ群54256083

10 IOT,win10iot 1.C#跨平台物联网通信框…

4.2.3    发送和选择数据事例… 3

4.3           开垦设备驱动… 3

4.3.1    构建实时数据长久对象(不是必需卡塔尔… 3

4.3.2    创设参数数据悠久对象… 5

4.3.3    营造发送和解析左券命令对象… 5

4.3.4    创设筑协会谈商讨驱动对象… 6

4.3.5    创设设备驱动对象… 8

4.4           构建宿主程序… 12

4.5           运营作效果果… 15

 

 

4.如开拓后生可畏套设备驱动,同一时间辅助串口和互联网通信

4.1    概述

    
作为物联网通信框架,料定要扶植各个简报链路,在二种电视发表链路的底蕴上达成二种报道左券的相互,举个例子:Modbus、自定义和煦等等。可是,有二个主题素材:针对同生龙活虎台硬件设施或传感器,落成串口和互联网三种简报格局的数据搜集和垄断,是不是要分头写代码?假诺从现实角度解析,同风流倜傥硬件,它要水到渠成的政工逻辑分明是同黄金年代的,所以ServerSuperIO物联网框架,允许开拓后生可畏套装置驱动,同有时候扶持串口和网络两种简报方式的交互作用。

    
通信很简短、交互作用很简短、业务很简短……假使把过多简约的难点合在一同,那么就变得不轻易了,所以要有三个框架性的东西,重新把广大题目变得轻易。

4.2    通信公约分明

   
在成功三个装置驱动的开荒以前,首先要领会它的简报合同,好比多个人沟通的言语同样。针对报导合同,大家自定义多少个简便交互作用情势,只是发送命令,提取数据信息。

4.2.1    发送读实时数据命令合同

    
Computer发送0x61发令为读实时数据命令,共发送6个字节,校验和为从“从机地址”开头的丰裕和,不满含“数据报头”、“校验和”和“合同结束”。

     发送指令数据帧如下:

帧结构

数码报头

从机地址

命令代码

校验和

讨论截至

0x55

0xAA

 

0x61

 

0x0D

字节数

1

1

1

1

1

1

  

4.2.2    拆解剖判实时数据合同

   
下位机采用到读实时数据命令后,并校验成功,重回实时数据,校验和为从“从机地址”起头的增加和,不富含“数据报头”、“校验和”和“合同甘休”。

    采取数据帧如下:

帧结构

数量报头

从机地址

指令代码

流量

信号

校验和

磋商结束

0x55

0xAA

 

0x61

浮点型

浮点型

 

0x0D

字节数

1

1

1

1

4

 

4

1

1

4.2.3    发送和选择数据事例

出殡(十四进制卡塔尔:0x55 0xaa 0x00 0x61 0x61 0x0d

收纳(十八进制卡塔尔:0x55 0xaa 0x00 0x61 0x43 0x7a 0x00 0x00 0x43 0xb4 0x15
0x0d

流量数据为:250.00

能量信号数据为:360.00

4.3    开垦设备驱动

4.3.1    营造实时数据持久对象(不是必得卡塔 尔(英语:State of Qatar)

1.由此重返数据的报道合同,有流量和能量信号四个动态变量,大家需求创建贰个动态指标实体类,主要用以合同驱动与设备驱动之间的数额交互作用。代码如下:

public class Dyn
{
        private float _Flow = 0.0f;
        /// <summary>
        /// 流量
        /// </summary>
        public float Flow
        {
            get { return _Flow; }
            set { _Flow = value; }
        }
        private float _Signal = 0.0f;
        /// <summary>
        /// 信号
        /// </summary>
        public float Signal
        {
            get { return _Signal; }
            set { _Signal = value; }
        }
}

 
2.我们第大器晚成的干活是要开创一个实时数据持久对象类,实时缓存数据音讯,也得以把该实时数据消息保存到数据库中或任何存款和储蓄媒介物。实时数据持久对象类的代码如下:

public class DeviceDyn:DeviceDynamic
{
        public DeviceDyn() : base()
        {
            Dyn=new Dyn();
        }
        public override string GetAlertState()
        {
            throw new NotImplementedException("无报警信息");
        }
        public override object Repair()
        {
            return new DeviceDyn();
        }
        public Dyn Dyn { get; set; }
}

     DeviceDyn
类世襲自DeviceDynamic,因为每一种硬件配备的报告警察方新闻有相当的大可能率不相似,所以GetAlertState函数能够实该成效,但是SSIO框架并不曾一向援用;这些类精气神上是一个足以类别化,在不加互斥的情况下可能招致文件损坏,所以Repair能够完毕修复效果,在DeviceDynamic基类里达成了该意义;其余,完毕DeviceDynamic基类自带多个函数,Save函数用于长久化(系列化卡塔尔国此类的消息,Load用于获取(反类别化卡塔 尔(阿拉伯语:قطر‎此类的音讯,在设备驱动中能够使用。

4.3.2    创设参数数据长久对象

   
经常的话硬件器械会有读参数的一声令下,那么重返来的参数也供给实行持久化存款和储蓄,而且每台设备的参数都大概不平等,在那提供三个可扩展的接口。在此个报导公约中并未关系到设备参数相关的磋商表达,可是大家也急需创立一个参数数据长久对象类,能够不写任何扩展的参数属性,在SSIO框架对参数的接口进行了援用,那是必需开展了劳作。代码如下:

public class DevicePara:ServerSuperIO.Device.DeviceParameter
{
        public override object Repair()
        {
            return new DevicePara();
        }
}

    
DevicePara世襲自DeviceParameter类,景况与实时数据漫长对象相同,可以参数。

4.3.3    创设发送和解析合同命令对象

   
与设备实行交互作用会涉及到多数交互作用式的命令或指令代码,而那几个命令在SSIO框架内是以左券命令对象的花样存在,大要包涵多少个部:推行命令接口、打包发送数据接口、拆解深入分析接受数据接口等。

   
针对地方的通信左券,有三个61命令,那么咱们就可以依照61指令为命名营造四个体协会谈商讨命令对象,包罗发送数据和剖判数据部分。假诺有其余命令代码,推而广之。代码如下:

internal class DeviceCommand:ProtocolCommand
{
        public override string Name
        {
            get { return "61"; }
        }

        public override void ExcuteCommand<T>(T t)
        {
            throw new NotImplementedException();
        }

        public override byte[] Package<T> (string code, T1 t1,T2 t2)
        {
            //发送:0x55 0xaa 0x00 0x61 0x61 0x0d
            byte[] data = new byte[6];
            data[0] = 0x55;
            data[1] = 0xaa;
            data[2] = byte.Parse(code);
            data[3] = 0x61;
            data[4] = this.ProtocolDriver.GetCheckData(data)[0];
            data[5] = 0x0d;
            return data;
        }

        public override dynamic Analysis<T>(byte[] data, T t)
        {
            Dyn dyn = new Dyn()
            //一般下位机是单片的话,接收到数据的高低位需要互换,才能正常解析。
            byte[] flow = BinaryUtil.SubBytes(data, 4, 4, true);
            dyn.Flow = BitConverter.ToSingle(flow, 0);
            byte[] signal = BinaryUtil.SubBytes(data, 8, 4, true);
            dyn.Signal = BitConverter.ToSingle(signal, 0);
            return dyn;
        }

}

    
构建筑协会议命令须求全部后续自ProtocolCommand,依据报道左券明确,Name属性重临61,作为首要字;Package是包装要送的数码消息;Analysis对应着选用数据之后实行剖析操作。就那样四个粗略的说道命令驱动就营造形成了。

4.3.4    营造筑组织商驱动对象

   
有了商业事务命令之后,我们要求构建筑组织商驱动对象,SSIO框架补助自定义讨论也在于此,并且与设施驱动的接口相关联,在SSIO框架的高端应用中也开展了援用,创设那引对象超级重大。代码如下:

internal class DeviceProtocol:ProtocolDriver
{
        public override bool CheckData(byte[] data)
        {
            if (data[0] == 0x55 && data[1] == 0xaa && data[data.Length - 1] == 0x0d)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public override byte[] GetCommand(byte[] data)
        {
            return new byte[] { data[3] };
        }

        public override int GetAddress(byte[] data)
        {
            return data[2];
        }

        public override byte[] GetHead(byte[] data)
        {
            return new byte[] { data[0], data[1] };
        }

        public override byte[] GetEnd(byte[] data)
        {
            return new byte[] { data[data.Length - 1] };
        }

        public override byte[] GetCheckData(byte[] data)
        {
            byte checkSum = 0;
            for (int i = 2; i < data.Length - 2; i++)
            {
                checkSum += data[i];
            }
            return new byte[] { checkSum };
        }

        public override string GetCode(byte[] data)
        {
            throw new NotImplementedException();
        }

        public override int GetPackageLength(byte[] data, IChannel channel, ref int readTimeout)
        {
           throw new NotImplementedException();
        }
}

     DeviceProtocol 合同驱动世袭自ProtocolDriver
,两个设备驱动只存在贰个体协会谈商讨驱动,贰个体协会谈商讨驱动能够存在八个斟酌命令(如61发令卡塔尔国。该类中的CheckData函数很入眼,SSIO框架中的设备驱动基类引用了,主倘若水到渠成校验选取数据的完事性,是或不是契合协议,进而决定了通讯状态:通信平常、通信中断、通信苦闷、以致通信未知,不相同的简报状态也调控了调用设备驱动中的哪个函数接口:Communicate、CommunicateInterrupt、CommunicateError和CommunicateNone。

4.3.5    营造设备驱动对象

    
下边的幼功工作都做完之后,现在就创设设备驱动的主干部分,也正是SSIO框架与设施驱动对接、谐和、调整的唯大器晚成接口,写完那些接口,设备驱动就足以在SSIO上直接运维了,而且与硬件器材开展相互。间接上代码:

public class DeviceDriver:RunDevice
{
        private DeviceDyn _deviceDyn;
        private DevicePara _devicePara;
        private DeviceProtocol _protocol;
        public DeviceDriver() : base()
        {
            _devicePara = new DevicePara();
            _deviceDyn = new DeviceDyn();
            _protocol = new DeviceProtocol();
        }

        public override void Initialize(string devid)
        {
            this.Protocol.InitDriver(this.GetType(),null);
            //初始化设备参数信息
            _devicePara.DeviceID = devid;//设备的ID必须先赋值,因为要查找对应的参数文件。
            if (System.IO.File.Exists(_devicePara.SavePath))
            {
                //如果参数文件存在,则获得参数实例
                _devicePara = _devicePara.Load<DevicePara>();
            }
            else
            {
                //如果参数文件不存在,则序列化一个文件
                _devicePara.Save<DevicePara>(_devicePara);
            }

            //初始化设备实时数据信息
            _deviceDyn.DeviceID = devid;//设备的ID必须先赋值,因为要查找对应的实时数据文件。
            if (System.IO.File.Exists(_deviceDyn.SavePath))
            {
                //参数文件存在,则获得参数实例
                _deviceDyn = _deviceDyn.Load<DeviceDyn>();
            }
            else
            {
                //如果参数文件不存在,则序列化一个文件
                _deviceDyn.Save<DeviceDyn>(_deviceDyn);
            }
        }

        public override byte[] GetConstantCommand()
        {
            return this.Protocol.DriverPackage<String>("0", "61", null);
        }

        public override void Communicate(ServerSuperIO.Communicate.IRequestInfo info)
        {
            Dyn dyn = this.Protocol.DriverAnalysis<String>("61", info.Data, null);
            if (dyn != null)
            {
                _deviceDyn.Dyn = dyn;
            }
            OnDeviceRuningLog("通讯正常");
        }

        public override void CommunicateInterrupt(ServerSuperIO.Communicate.IRequestInfo info)
        {
            OnDeviceRuningLog("通讯中断");
        }

        public override void CommunicateError(ServerSuperIO.Communicate.IRequestInfo info)
        {
            OnDeviceRuningLog("通讯干扰");
        }

        public override void CommunicateNone()
        {
            OnDeviceRuningLog("通讯未知");
        }

        public override void Alert()
        {
            return;
        }

        public override void Save()
        {
            try
            {
                _deviceDyn.Save<DeviceDyn>(_deviceDyn);
            }
            catch (Exception ex)
            {
                OnDeviceRuningLog(ex.Message);
            }
        }

        public override void Show()
        {
            List<string> list=new List<string>();
            list.Add(_devicePara.DeviceName);
            list.Add(_deviceDyn.Dyn.Flow.ToString());
            list.Add(_deviceDyn.Dyn.Signal.ToString());
            OnDeviceObjectChanged(list.ToArray());
        }

        public override void UnknownIO()
        {
            OnDeviceRuningLog("未知通讯接口");
        }

        public override void CommunicateStateChanged(ServerSuperIO.Communicate.CommunicateState comState)
        {
            OnDeviceRuningLog("通讯状态改变");
        }

        public override void ChannelStateChanged(ServerSuperIO.Communicate.ChannelState channelState)
        {
            OnDeviceRuningLog("通道状态改变");
        }

        public override void Exit()
        {
            OnDeviceRuningLog("退出设备");
        }

        public override void Delete()
        {
            OnDeviceRuningLog("删除设备");
        }

        public override object GetObject()
        {
            throw new NotImplementedException();
        }

        public override void ShowContextMenu()
        {
            throw new NotImplementedException();
        }

        public override IDeviceDynamic DeviceDynamic
        {
            get { return _deviceDyn; }
        }

        public override IDeviceParameter DeviceParameter
        {
            get { return _devicePara; }
        }

        public override IProtocolDriver Protocol
       {
            get { return _protocol;}
        }

        public override DeviceType DeviceType
        {
            get { return DeviceType.Common; }
        }

        public override string ModelNumber
        {
            get { return "serversuperio"; }
        }

        public override System.Windows.Forms.Control DeviceGraphics
        {
            get { throw new NotImplementedException(); }
        }
}

   
实时动态数据对象_deviceDyn、参数数据对象_devicePara、协议驱动对象_protocol分别提要求接口:DeviceDynamic、DeviceParameter和Protocol,为SSIO提供可援用的基础属性参数。

    
Initialize是设备驱动开始化的函数接口,在这里个接口完结五个举足轻重办事:起先化协议驱动和参数性的音讯。通过this.Protocol.InitDriver(this.GetType(),null);代码能够加载全数左券命令到协商驱动的缓存中,以便实时调用。当然这里边也得以开展其余地点的行事,可是注意对丰盛的拍卖。

    
DeviceType那一个是器材的花色,经常钦命为Common就好了。其余函数接口成效已经在《物联网框架ServerSuperIO教程-3.设备驱动介绍》中详尽介绍了,请参见。

4.4    营造宿主程序

    
一个轻松的装置驱动就已经支付好了,光有驱动还特别,那么大家根据SSIO框架再写几行代码,落成贰个宿主程序,把设备驱动实例化,放SSIO的劳动实例中运营,达成串口和网络二种办法的通信人机联作,代码也特别轻易。代码如下:

class Program
{
        static void Main(string[] args)
        {
            DeviceDriver dev1 = new DeviceDriver();
            dev1.DeviceParameter.DeviceName = "串口设备1";
            dev1.DeviceParameter.DeviceAddr = 0;
            dev1.DeviceParameter.DeviceID = "0";
            dev1.DeviceDynamic.DeviceID = "0";
            dev1.DeviceParameter.COM.Port = 1;
            dev1.DeviceParameter.COM.Baud = 9600;
            dev1.CommunicateType = CommunicateType.COM;
            dev1.Initialize("0");

            DeviceDriver dev4 = new DeviceDriver();
            dev4.DeviceParameter.DeviceName = "网络设备2";
            dev4.DeviceParameter.DeviceAddr = 0;
            dev4.DeviceParameter.DeviceID = "3";
            dev4.DeviceDynamic.DeviceID = "3";
            dev4.DeviceParameter.NET.RemoteIP = "127.0.0.1";
            dev4.DeviceParameter.NET.RemotePort = 9600;
            dev4.CommunicateType = CommunicateType.NET;
            dev4.Initialize("3");

            IServer server = new ServerFactory().CreateServer(new ServerConfig()
            {
                ServerName = "服务实例1",
                SocketMode = SocketMode.Tcp,
                ControlMode = ControlMode.Loop,
                CheckSameSocketSession = false,
                StartCheckPackageLength = false,
            });

            server.AddDeviceCompleted += server_AddDeviceCompleted;
            server.DeleteDeviceCompleted += server_DeleteDeviceCompleted;
            server.SocketConnected+=server_SocketConnected;
            server.SocketClosed+=server_SocketClosed;
            server.Start();

            server.AddDevice(dev1);
            server.AddDevice(dev4);

            while ("exit"==Console.ReadLine())
            {
                 server.Stop();
            }
        }

        private static void server_SocketClosed(string ip, int port)
        {
            Console.WriteLine(String.Format("断开:{0}-{1} 成功", ip, port));
        }

        private static void server_SocketConnected(string ip, int port)
        {
            Console.WriteLine(String.Format("连接:{0}-{1} 成功",ip, port));
        }

        private static void server_AddDeviceCompleted(string devid, string devName, bool isSuccess)

        {
            Console.WriteLine(devName+",增加:"+isSuccess.ToString());
        }

        private static void server_DeleteDeviceCompleted(string devid, string devName, bool isSuccess)
        {
            Console.WriteLine(devName + ",删除:" + isSuccess.ToString());
        }
    }
}

    
那么些代码大家都能看驾驭,具体的决定情势大家接下去会相继介绍。在营造宿主程序的时候,切忌对服务实例那样援用:server.ChannelManager、server.ControllerManager、server.DeviceManager。固然提供了那般的接口,首假如为了SSIO框架之中使用的,无需大家单独去操作那么些接口。有的网民是这么的写的,那么就改成了叁个纯的通讯IO框架,那么就错失了SSIO框架本人的股票总值。作为贰遍开荒者,只须要安装设备驱动的参数,以至向服务实例中扩张或删除设备就能够了,别的具有的运作总体付出SSIO框架来产生。

4.5    运营效果

 图片 4

 

1.[连载]《C#简报(串口和互连网卡塔 尔(阿拉伯语:قطر‎框架的宏图与得以达成》

2.[开源]C#跨平台物联网通信框架ServerSuperIO(SSIO卡塔尔介绍

2.使用SuperIO(SIO卡塔 尔(阿拉伯语:قطر‎和开源跨平台物联网框架ServerSuperIO(SSIO卡塔 尔(阿拉伯语:قطر‎塑造系统的总体方案

3.C#工业物联网和集成系统设计方案的才干路子(数据源、数据搜罗、数据上传与选择、ActiveMQ、Mongodb、WebApi、手机App卡塔 尔(英语:State of Qatar)

5.ServerSuperIO开源地址:

物联网&集成才具(.NET) QQ群54256083

发表评论