1.C#跨平台物联网通讯框架ServerSuperIO(SSIO)介绍
《连载 |
物联网框架ServerSuperIO教程》1.4种简报模式机制。
永利皇宫463手机版,《连载 |
物联网框架ServerSuperIO教程》2.劳动实例的配置参数表达
《连载 | 物联网框架ServerSuperIO教程》-
3.器具驱动介绍
注:ServerSuperIO有希望被移植到Windows
10
IOT上,那么以后有希望开荒一套设备驱动,能够分段在服务端、嵌入式设备中,将产生完整的消除方案。
现在已经调试通过某个代码,还得需求一段时间,日常都以晚上干,时间也轻松。如下图:
目 录
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
4.如开辟一套设备驱动,同期援助串口和互联网通信
4.1 概述
作为物联网通信框架,分明要补助三种通讯链路,在各类简报链路的底子上成功种种简报公约的竞相,举个例子:Modbus、自定义商量等等。可是,有一个题目:针对同一台硬件设备或传感器,完结串口和网络三种简报方式的多少收集和调整,是或不是要分头写代码?举个例子从实际角度解析,同一硬件,它要到位的事情逻辑分明是一模二样的,所以ServerSuperIO物联网框架,允许开采一套装置驱动,同一时候帮忙串口和网络两种简报情势的并行。
通信很粗大略、交互很轻易、业务很轻易……借使把好多大概的标题合在一同,那么就变得不简单了,所以要有贰个框架性的事物,重新把众多主题材料变得轻易。
4.2 通讯公约规定
在成功二个装置驱动的开销在此之前,首先要精晓它的简报合同,好比五个人调换的语言一样。针对报纸发表契约,大家自定义三个简单交互方式,只是发送命令,提取数额新闻。
4.2.1 发送读实时数据命令公约
计算机发送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 塑造实时数据长久对象(不是必得)
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 运维效果
1.[连载]《C#广播发表(串口和互联网)框架的布署性与贯彻》
2.[开源]C#跨平台物联网通信框架ServerSuperIO(SSIO)介绍
2.行使SuperIO(SIO)和开源跨平台物联网框架ServerSuperIO(SSIO)营造系统的欧洲经济共同体方案
3.C#工业物联网和集成系统施工方案的手艺门路(数据源、数据搜聚、数据上传与接受、ActiveMQ、Mongodb、WebApi、手提式有线电电话机App)
5.ServerSuperIO开源地址:
物联网&集成技艺(.NET) QQ群:54256083