驱动开发实战之TcpClient

场景模拟

假设你有一批非标设备需要对接,你需要根据设备方提供的协议,为IoTGateway开发驱动,进行数据交互。

文章比较长也可以到官网会有更好的体验,地址:

http://iotgateway.net/docs/iotgateway/driver/tcpclient

请先浏览上一篇驱动简介

http://iotgateway.net/docs/iotgateway/driver/drvier

协议概述

对方提供了如下协议文档:

设备作为TCPServer,端口6666 字节序:Little-Endian,即低地址存放低位

请求回复

需要你主动发起读取请求:0x01 02 03 04 设备回复:0x08 01 41 D6 3D 71 1A 20

参数说明

  1. 总字节数

    (byte[0])即0x08:用于简单的校验

  2. 运行状态

    (byte[1])即0x01:1为运行;其他为停止

  3. 设备温度

    (byte[2]-byte[5])即0x41 D6 3D 71:单精度浮点数值26.78

  4. 电机转速

    (byte[6]-byte[7])即0x1A 20:对应16进制无符号整型,倍率0.01值66.88

驱动开发

创建驱动项目

  1. 在解决方案->Drivers文件夹,右键添加->新建项目->C#类库 7c040849bf82883f7fb59fe3bdf69e88.png

  2. 项目名DriverSimTcpClient,放在iotgateway\Plugins\Drivers路径下 d908dbd43e5e2d9c4e4fe2f598e630fe.png

  3. 修改Class1SimTcpClient

  4. 双击项目,修改配置 21f1a4cc8347cf7032a294d40900712a.png

    iotgateway\Plugins\Drivers\DriverSimTcpClient\DriverSimTcpClient.csproj

    <Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><TargetFramework>net6.0</TargetFramework><OutputPath>../../../IoTGateway/bin/Debug/net6.0/drivers</OutputPath><CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies><ImplicitUsings>enable</ImplicitUsings><Nullable>enable</Nullable></PropertyGroup><ItemGroup><PackageReference Include="SimpleTCP.Core" Version="1.0.4" /></ItemGroup><ItemGroup><ProjectReference Include="..\..\PluginInterface\PluginInterface.csproj" /></ItemGroup>
    </Project>

说明:

OutputPath节点指定了生成项目的文件夹

SimpleTCP.Core是一个TCP客户端库(你也可以自己写)

ProjectReference节点引用了PluginInterface项目

CopyLocalLockFileAssemblies节点可以确保你引用的nuget拷贝到driver文件夹下 :::

编写项目代码:

iotgateway\Plugins\Drivers\DriverSimTcpClient\SimTcpClient.cs

using PluginInterface;
using SimpleTCP;
using System;
using System.Text;
namespace DriverSimTcpClient
{[DriverSupported("SimTcpServerDevice")][DriverInfoAttribute("SimTcpClient", "V1.0.0", "Copyright iotgateway© 2022-06-04")]public class SimTcpClient : IDriver{/// <summary>/// tcp客户端/// </summary>private SimpleTcpClient? client;/// <summary>/// 缓存最新的服务器返回的原始数据/// </summary>private byte[] latestRcvData;#region 配置参数[ConfigParameter("设备Id")]public Guid DeviceId { get; set; }[ConfigParameter("IP地址")]public string IpAddress { get; set; } = "127.0.0.1";[ConfigParameter("端口号")]public int Port { get; set; } = 6666;/// <summary>/// 为了演示枚举类型在web端的录入,这里没用到 但是你可以拿到/// </summary>[ConfigParameter("连接类型")]public ConnectionType ConnectionType { get; set; } = ConnectionType.Long;[ConfigParameter("超时时间ms")]public int Timeout { get; set; } = 300;[ConfigParameter("最小通讯周期ms")]public uint MinPeriod { get; set; } = 3000;#endregionpublic SimTcpClient(Guid deviceId){DeviceId = deviceId;}/// <summary>/// 判断连接状态/// </summary>public bool IsConnected{get{//客户端对象不为空并且客户端已连接则返回truereturn client != null && client.TcpClient.Connected;}}/// <summary>/// 进行连接/// </summary>/// <returns>连接是否成功</returns>public bool Connect(){try{//进行连接client = new SimpleTcpClient().Connect(IpAddress, Port);client.DataReceived += Client_DataReceived;}catch (Exception){return false;}return IsConnected;}/// <summary>/// 收到服务端数据/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Client_DataReceived(object? sender, Message e){//如果收到的数据校验正确,则放在内存中if (e.Data.Length == 8 && e.Data[0] == 0x08)latestRcvData = e.Data;}/// <summary>/// 断开连接/// </summary>/// <returns>断开是否成功</returns>public bool Close(){try{client.DataReceived -= Client_DataReceived;//断开连接client?.Disconnect();return !IsConnected;}catch (Exception){return false;}}/// <summary>/// 释放/// </summary>public void Dispose(){try{//释放资源client?.Dispose();}catch (Exception){}}/// <summary>/// 发送数据/// </summary>private byte[] sendCmd = new byte[4] { 0x01, 0x02, 0x03, 0x04 };/// <summary>/// 解析并返回/// </summary>/// <param name="ioarg">ioarg.Address为起始变量字节编号;ioarg.ValueType为类型</param>/// <returns></returns>[Method("读模拟设备数据", description: "读模拟设备数据,开始字节和长度")]public DriverReturnValueModel Read(DriverAddressIoArgModel ioarg){var ret = new DriverReturnValueModel { StatusType = VaribaleStatusTypeEnum.Good };ushort startIndex;//判断地址是否为整数if (!ushort.TryParse(ioarg.Address, out startIndex)){ret.StatusType = VaribaleStatusTypeEnum.Bad;ret.Message = "起始字节编号错误";return ret;}//连接正常则进行读取if (IsConnected){try{//发送请求client?.Write(sendCmd);//等待恢复,这里可以优化Thread.Sleep(Timeout);if (latestRcvData == null){ret.StatusType = VaribaleStatusTypeEnum.Bad;ret.Message = "没有收到数据";}else{//解析数据,并返回switch (ioarg.ValueType){case DataTypeEnum.UByte:case DataTypeEnum.Byte:ret.Value = latestRcvData[startIndex];break;case DataTypeEnum.Int16:var buffer16 = latestRcvData.Skip(startIndex).Take(2).ToArray();ret.Value = BitConverter.ToInt16(new byte[] { buffer16[0], buffer16[1] }, 0);break;case DataTypeEnum.Float://拿到有用的数据var buffer32 = latestRcvData.Skip(startIndex).Take(4).ToArray();//大小端转换一下ret.Value = BitConverter.ToSingle(new byte[] { buffer32[3], buffer32[2], buffer32[1], buffer32[0] }, 0);break;default:break;}}}catch (Exception ex){ret.StatusType = VaribaleStatusTypeEnum.Bad;ret.Message = $"读取失败,{ex.Message}";}}else{ret.StatusType = VaribaleStatusTypeEnum.Bad;ret.Message = "连接失败";}return ret;}public async Task<RpcResponse> WriteAsync(string RequestId, string Method, DriverAddressIoArgModel Ioarg){RpcResponse rpcResponse = new() { IsSuccess = false, Description = "设备驱动内未实现写入功能" };return rpcResponse;}}public enum ConnectionType{Long,Short}
}

注册驱动

  1. 生成DriverSimTcpClient 项目

    iotgateway\IoTGateway\bin\Debug\net6.0\drivers\net6.0路径下可以看到生成了DriverSimTcpClient.dll

  2. 运行IoTGateway,访问本地518端口

  3. 添加驱动

网关配置->驱动管理->添加

6e582cba306714982e65949ff3c7544e.png

注意:添加驱动后需要重启一下项目,后面会优化

创建设备

采集配置->设备维护->添加设备

 a19152f349a35b6c859afc64080d8b54.png

添加变量

采集配置->设备维护->添加设备

手动添加或者通过excel批量导入下面变量

变量名方法地址类型表达式设备名
运行状态Read1uint8
模拟设备
设备温度Read2float
模拟设备
电机转速Read6int16raw*0.01模拟设备

开始采集

采集配置->设备维护->编辑设备 cff95584ef6e2e4a7ba33dcabcb0dbb1.png

启动TcpServer

运行你熟悉的TCPServer测试工具,启动端口6666,网关客户端连接后发送响应报文

6806f1df7841dede03934362b512265f.png

查看数据

75938eafdf47e8d4581d61ae85d7d298.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/286442.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【遥感数字图像处理实验】Erdas版详细图文实验教程(8实验全)

文章目录1. 专栏简介2. 专栏地址3. 专栏目录1. 专栏简介 遥感数字图像的处理&#xff0c;是对遥感数字图像的计算机处理。与工业和医学数字图像不同&#xff0c;遥感数字图像类型更为多样&#xff0c;内容更为复杂。因此&#xff0c;遥感数字图像的处理&#xff0c;不仅需要掌握…

WEBAPI 增加身份验证 (OAUTH 2.0方式)

1&#xff0c;在Webapi项目下添加如下引用&#xff1a;Microsoft.AspNet.WebApi.OwinOwinMicrosoft.Owin.Host.SystemWebMicrosoft.Owin.Security.OAuthMicrosoft.Owin.Security.CookiesMicrosoft.AspNet.Identity.OwinMicrosoft.Owin.Cors2&#xff0c; 在项目下新建Startup类…

无代码iVX编程实现简单 小蜜蜂 经典游戏

首先咱们打开 iVX 的在线编辑器&#xff1a;https://editor.ivx.cn/ 随后选择相对定位&#xff0c;咱们选择2D游戏类型制作一个简单小蜜蜂游戏&#xff1a; 接着咱们创建一个物理世界&#xff0c;并且将页面布局如以下&#xff1a; 以上布局中&#xff0c;矩形为模拟飞机、…

【无人机航空摄影测量精品教程】目录:Pix4d、EPS、CC、PhotoScan、Godwork项目化作业流程及注意事项汇总

文章目录1. 专栏简介2. 专栏地址3. 专栏目录1. 专栏简介 该专栏为目前最为热门的无人机航测内外业项目&#xff0c;主要内容包括&#xff1a;无人机航测外业作业流程&#xff08;像控点布设、航线规划、仿地飞行、航拍&#xff09;和内业数据处理软件&#xff08;Pix4d、CC、EP…

WPF 基础控件之 Slider 样式

其他基础控件1.Window2.Button3.CheckBox4.ComboBox5.DataGrid 6.DatePicker7.Expander8.GroupBox9.ListBox10.ListView11.Menu12.PasswordBox13.TextBox14.RadioButton15.ToggleButtonSlider 实现下面的效果1&#xff09;Slider来实现动画&#xff1b;Grid嵌套 Border并设置S…

SQL 通过syscolumns.xtype动态查找指定数据类型字段所包含的数据

表中太多列&#xff0c;只想查找某些比如&#xff0c;数据类型为varchar的字段的数据。 思路&#xff1a;1、先获取列名&#xff1a; select * from syscolumns where id(select max(id) from sysobjects where xtypeu and nametest_A)2、查找指定数据类型&#xff0c;xtype就…

css案例学习之span边框实现的特殊效果

bottom left bottom right top left top right 配合颜色来使用&#xff0c;实现一些神奇的效果 #menu a span{height:0;width:0;/*border-top:solid 6px #fff;border-left:solid 6px #f90;*//*border-top:solid 6px #fff;border-right:solid 6px #f90;*//*border-bottom:solid …

网页版消消乐快速实现,无代码吗iVX 真那么简单?

最近没事想做个消消乐&#xff0c;然后听说 iVX 免费了&#xff0c;所以又跑去看看 iVX 了&#xff0c;就用一个无代码来看看消消乐怎么玩吧。 首先咱们打开 iVX 的在线编辑器&#xff1a;https://editor.ivx.cn/ 随后咱们不需要游戏类型也可以制作一个消消乐游戏&#xff1a…

虚拟化记录--No.1

近段时间&#xff0c;会花些时间做关于系统虚拟化的工作。所以会做一些这样的记录。相信很多东西不会特别成体系&#xff0c;每个人因为关注的不同而记录和学习的重点也会有比较大的出入。这篇是NO.1(注意不是TOP 1 )真的是由于对于ORACLE很有感觉&#xff0c;所以上手去做的也…

C# Java间进行RSA加密解密交互

这里&#xff0c;讲一下RSA算法加解密在C#和Java之间交互的问题&#xff0c;这两天纠结了很久&#xff0c;也看了很多其他人写的文章&#xff0c;颇受裨益&#xff0c;但没能解决我的实际问题&#xff0c;终于&#xff0c;还是被我捣鼓出来了。 首先&#xff0c;介绍一下写这代…

【Microstation】三维建模基础及软件入门到精通实验教程目录

文章目录1. 专栏简介2. 专栏地址3. 专栏目录1. 专栏简介 MicroStation是一款非常不错的二维和三维设计软件&#xff0c;由奔特力&#xff08;Bentley&#xff09;工程软件系统有限公司开发的一款软件。在CAD设计上该软件是和AutoCAD是齐名的软件&#xff0c;其专用的文件格式是…

无代码iVX编程实现简单魂斗罗

首先咱们打开 iVX 的在线编辑器&#xff1a;https://editor.ivx.cn/ 随后咱们选择2D游戏类型制作一个简单魂斗罗游戏&#xff1a; 随后咱们开始创建一个物理世界&#xff0c;不并且在物理世界之下创建一个一个图片添加物体属性&#xff0c;在物体属性中更改对应的属性内容&am…

【ArcGIS遇上Python】ArcGIS Python批处理入门到精通实用教程目录

文章目录1. 专栏简介2. 专栏地址3. 专栏目录1. 专栏简介 Python语言是目前很火热的语言&#xff0c;极大的促进了人工智能发展。你知道在ArcGIS中也会有python的身影吗&#xff1f;事实上&#xff0c;在ArcGIS中使用Python会起到事半功倍的效果&#xff0c;大大提高工作效率&am…

Android使用C/C++来保存密钥

Android使用C/C来保存密钥本文主要介绍如何通过native方法调用取出密钥&#xff0c;以替代原本直接写在Java中&#xff0c;或写在gradle脚本中的不安全方式。为什么要这么做 如果需要在本地存储一个密钥串&#xff0c;典型的方式有 1. 直接写在java source code中 2. 写在gradl…

无代码iVX编程实现简单跳跃超级玛丽游戏

首先咱们打开 iVX 的在线编辑器&#xff1a;https://editor.ivx.cn/ 随后咱们选择2D游戏类型制作一个简单跳跃游戏&#xff1a; 接下来创建几个图片&#xff0c;并且添加物体&#xff0c;如图所示&#xff1a; 在此需要更改对应称重地面的阻尼值&#xff0c;让其能够缓慢降落…

【三维激光扫描】实验01:环境搭建CAD2014+StonexSiScan软件安装

目 录 一、CAD2014简体中文版安装1. 安装过程2. 激活过程二、Si-Scan安装1. 主程序安装2. 驱动安装一、CAD2014简体中文版安装 1. 安装过程 双击安装包:AutoCAD_2014_Simplified_Chinese_Win_64bit_dlm.sfx.exe,进行自解压。 解压完成后,如下图所示,点击【安装】。 接受许…

C# 11 新特性:原始字符串

之前我们经常需要使用 string 类型定义字符串文本&#xff0c;字符串文本用一对双引号括起来表示&#xff1a;var str "Hello MyIO";字符串可包含任何字符文本&#xff0c;但是有些字符需要转义才能表示&#xff0c;比如双引号要转义成\"&#xff1a;var str …

bzoj1011

因为允许5%的误差。。所以把&#xff1e;一定长度的一段看成一段近似计算就行了。。 1 #include<cstdio>2 #include<cstdlib>3 #include<cstring>4 #include<ctime>5 #include<cmath>6 #include<iostream>7 #include<algorithm>8 #i…

一名全栈工程师的必备“百宝箱”

摘要&#xff1a;全栈工程师&#xff0c;也叫全端工程师&#xff0c;是指掌握多种技能&#xff0c;并能利用多种技能独立完成产品的人。全栈工程师熟悉多种开发语言&#xff0c;同时具备前端和后台开发能力&#xff0c;从需求分析&#xff0c;原型设计到产品开发&#xff0c;测…

为VMware虚拟主机添加新磁盘

轨迹: 关闭VMware虚拟主机 ---> 虚拟机 ---> 设置 ---> 硬件 ---> 硬盘 ---> 添加 ---> (弹出添加硬件向导)硬盘 ---> 磁盘类型 ---> 选择磁盘 ---> 指定磁盘容量(最好选择“将虚拟磁盘存储为单个文件”) ---> 指定磁盘文件 ---> 点击“完成…