Commit 7900e6fb 张东亮

左下层链条一直转问题

1 个父辈 f7e5ebdf
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16 # Visual Studio Version 17
VisualStudioVersion = 16.0.31613.86 VisualStudioVersion = 17.5.33414.496
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "source\Common\Common.csproj", "{43CDD09E-FCF3-4960-A01D-3BBFE9933122}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "source\Common\Common.csproj", "{43CDD09E-FCF3-4960-A01D-3BBFE9933122}"
EndProject EndProject
...@@ -15,8 +15,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ABBRobotTest", "source\ABBR ...@@ -15,8 +15,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ABBRobotTest", "source\ABBR
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DoubleLineClient", "source\DoubleLineClient_3D\DoubleLineClient.csproj", "{0D2542F5-DD62-4352-82D0-383D9A045E74}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DoubleLineClient", "source\DoubleLineClient_3D\DoubleLineClient.csproj", "{0D2542F5-DD62-4352-82D0-383D9A045E74}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DL.IOModule", "source\DL.IOModule\DL.IOModule.csproj", "{F85A7412-B5B3-4291-A448-A10564602E1A}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
...@@ -47,10 +45,6 @@ Global ...@@ -47,10 +45,6 @@ Global
{0D2542F5-DD62-4352-82D0-383D9A045E74}.Debug|Any CPU.Build.0 = Debug|Any CPU {0D2542F5-DD62-4352-82D0-383D9A045E74}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0D2542F5-DD62-4352-82D0-383D9A045E74}.Release|Any CPU.ActiveCfg = Release|Any CPU {0D2542F5-DD62-4352-82D0-383D9A045E74}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0D2542F5-DD62-4352-82D0-383D9A045E74}.Release|Any CPU.Build.0 = Release|Any CPU {0D2542F5-DD62-4352-82D0-383D9A045E74}.Release|Any CPU.Build.0 = Release|Any CPU
{F85A7412-B5B3-4291-A448-A10564602E1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F85A7412-B5B3-4291-A448-A10564602E1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F85A7412-B5B3-4291-A448-A10564602E1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F85A7412-B5B3-4291-A448-A10564602E1A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
......
using DL.Utils;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace DL.IOModule
{
/// <summary>
/// 零点IO模块操作类
/// </summary>
public class AIOBOX
{
/// <summary>
/// 自动读取DIO委托
/// </summary>
/// <param name="box">AIOBOX</param>
/// <param name="sta"></param>
public delegate void DIO_Changed(AIOBOX box, Box_Sta[] sta);
/// <summary>
/// 自动读取AIO委托
/// </summary>
/// <param name="box">AIOBOX</param>
/// <param name="val"></param>
public delegate void AIO_Changed(AIOBOX box, int[] val);
/// <summary>
/// 自动读取DI事件触发
/// </summary>
public event DIO_Changed DI_Changed_Event;
/// <summary>
/// 自动读取DO事件触发
/// </summary>
public event DIO_Changed DO_Changed_Event;
/// <summary>
/// 自动读取AI事件触发
/// </summary>
public event AIO_Changed AI_Changed_Event;
/// <summary>
/// 设备地址
/// </summary>
private byte equipAddr = 255;
private Com.TCP.ModbusTCPMaster _client; //客户端
private bool _loop;
private Box_Sta[] _stateDI; //DI状态
private Box_Sta[] _stateDO; //DO状态
private int[] _valueAI; //AI模拟量
private int[] _valueAO; //AO模拟量
private List<byte> _receive;
private IOType _typeInput; //输入类型
private IOType _typeOutput; //输出类型
private byte[] _addressInput; //输入地址
private byte[] _addressOutput; //输出地址
private const int SEND_SLEEP = 50; //每条命令发送的间隔
private const int PORT = 502; //端口
private const int UPLOAD_TIME = 3000; //5秒
private Thread tSend; //发送命令处理
/// <summary>
/// 零点IO模块操作类
/// 数字信号输入,离散输入,支持功能码为02,
/// 模拟量输入,输入寄存器,支持功能码为04,
/// 数字信号输出,线圈,支持功能码为01,05,15
/// </summary>
/// <param name="logName"></param>
public AIOBOX()
{
_client = new Com.TCP.ModbusTCPMaster();
_client.ReceiveData += _client_ReceiveData;
}
/// <summary>
/// 收到的数据解析
/// </summary>
/// <param name="ip"></param>
/// <param name="port"></param>
/// <param name="requestInfo"></param>
/// <param name="data"></param>
private void _client_ReceiveData(string ip, int port, Com.TCP.RequestInfo requestInfo, byte[] data)
{
int idx = 0;
int count=data.Length;
try
{
if(requestInfo.FunCode==1)//ReadDO
{
Box_Sta[] staDO = new Box_Sta[_stateDO.Length];
for (int i = 0; i < count; i++)
{
int move = 0;
byte val = data[i];
for (int j = 0; j < 8; j++) //字节的0-7位
{
int n = (val & Convert.ToInt32(Math.Pow(2, move))) >> move;
staDO[idx++] = n == 1 ? Box_Sta.On : Box_Sta.Off;
move++;
}
}
Array.Copy(staDO, 0, _stateDO, 0, staDO.Length);
DO_Changed_Event?.Invoke(this, staDO);
}
else if (requestInfo.FunCode == 2) //ReadDI
{
Box_Sta[] staDI = new Box_Sta[_stateDI.Length];
for (int i = 0; i < count; i++)
{
int move = 0;
byte val = data[i];
for (int j = 0; j < 8; j++) //字节的0-7位
{
int n = (val & Convert.ToInt32(Math.Pow(2, move))) >> move;
staDI[idx++] = n == 1 ? Box_Sta.On : Box_Sta.Off;
move++;
}
}
Array.Copy(staDI, 0, _stateDI, 0, staDI.Length);
DI_Changed_Event?.Invoke(this, staDI);
}
}
catch (Exception ex)
{
LogUtil.Error("ReceiveData", ex);
}
}
/// <summary>
/// IP地址
/// </summary>
public string IP { set; get; } = "192.168.1.100";
/// <summary>
/// 输入主动上传
/// </summary>
public bool Upload { set; get; } = false;
/// <summary>
/// DI总数
/// </summary>
public int InputCount
{
get
{
if (_addressInput == null)
return 0;
else
return _addressInput.Length;
}
}
/// <summary>
/// DO总数
/// </summary>
public int OutputCount
{
get
{
if (_addressOutput == null)
return 0;
else
return _addressOutput.Length;
}
}
/// <summary>
/// 设置输入输出的类型
/// </summary>
/// <param name="input"></param>
/// <param name="inputCount"></param>
/// <param name="output"></param>
/// <param name="outputCount"></param>
public void SetType(IOType input, int inputCount, IOType output, int outputCount)
{
_typeInput = input;
_typeOutput = output;
byte n = 0;
_addressInput = new byte[inputCount];
for (int i = 0; i < inputCount; i++)
_addressInput[i] = n++;
_addressOutput = new byte[outputCount];
for (int i = 0; i < outputCount; i++)
_addressOutput[i] = n++;
_stateDI = new Box_Sta[inputCount];
_stateDO = new Box_Sta[outputCount];
_valueAI = new int[inputCount];
_valueAO = new int[outputCount];
}
/// <summary>
/// 连接
/// </summary>
/// <returns></returns>
public bool Connect()
{
_loop = true;
bool rtn = Utils.HttpHelper.CheckIP(IP);
if (!rtn) return false;
_client.Connect(IP, PORT);
tSend = new Thread(new ThreadStart(Send)) { Name = "Send" };
tSend.IsBackground = true;
tSend.Start();
_client.AddRequest(GetReadDO_Command());
_client.AddRequest(GetReadInput_Command());
return true;
}
/// <summary>
/// 关闭连接
/// </summary>
public void Close()
{
_loop = false;
try
{
if (_client != null)
{
_client.Close();
}
}
finally
{
_client = null;
}
}
/// <summary>
/// 相反状态(ON/OFF)
/// </summary>
/// <param name="sta"></param>
/// <returns></returns>
public Box_Sta ReverseStatus(Box_Sta sta)
{
return sta == Box_Sta.On ? Box_Sta.Off : Box_Sta.On;
}
/// <summary>
/// 相反状态(ON/OFF)
/// </summary>
/// <param name="sta"></param>
public void ReverseStatus(ref Box_Sta sta)
{
if (sta == Box_Sta.On)
sta = Box_Sta.Off;
else
sta = Box_Sta.On;
}
/// <summary>
/// 读取单个DI输入状态(ON/OFF)
/// </summary>
/// <param name="add">输入地址,从0开始</param>
/// <returns></returns>
public Box_Sta ReadDI(int add)
{
return _stateDI[add];
}
/// <summary>
/// 读取多个DI输入状态(ON/OFF)
/// </summary>
/// <param name="add">起始地址,从0开始</param>
/// <param name="count">数量</param>
/// <returns></returns>
public Box_Sta[] ReadDI(int add, int count)
{
Box_Sta[] sta = new Box_Sta[count];
Array.Copy(_stateDI, add, sta, 0, count);
return sta;
}
/// <summary>
/// 读取单个AI模拟量的值
/// </summary>
/// <param name="add">模拟量地址,从0开始</param>
/// <returns></returns>
public int ReadAI(int add)
{
return _valueAI[add];
}
/// <summary>
/// 读取多个AI模拟量的值
/// </summary>
/// <param name="add">起始地址,从0开始</param>
/// <param name="count">数量</param>
/// <returns></returns>
public int[] ReadAI(int add, int count)
{
int[] sta = new int[count];
Array.Copy(_valueAI, add, sta, 0, count);
return sta;
}
/// <summary>
/// 读取单个DO输出状态(ON/OFF)
/// </summary>
/// <param name="add">输出地址,从0开始</param>
/// <returns></returns>
public Box_Sta ReadDO(int add)
{
return _stateDO[add];
}
/// <summary>
/// 读取多个DO输出状态(ON/OFF)
/// </summary>
/// <param name="add">起始地址,从0开始</param>
/// <param name="count">数量</param>
/// <returns></returns>
public Box_Sta[] ReadDO(int add, int count)
{
Box_Sta[] sta = new Box_Sta[count];
Array.Copy(_stateDO, add, sta, 0, count);
return sta;
}
/// <summary>
/// 读取单个AO模拟量的值
/// </summary>
/// <param name="add">输出地址,从0开始</param>
/// <returns></returns>
public int ReadAO(int add)
{
return _valueAO[add];
}
/// <summary>
/// 读取多个AO模拟量的值
/// </summary>
/// <param name="add">起始地址,从0开始</param>
/// <param name="count">数量</param>
/// <returns></returns>
public int[] ReadAO(int add, int count)
{
int[] sta = new int[count];
Array.Copy(_valueAO, add, sta, 0, count);
return sta;
}
/// <summary>
/// 写入单个DO输出状态(ON/OFF)。
/// 写单个线圈,功能码05
/// </summary>
/// <param name="add">输出地址,从0开始</param>
/// <param name="sta"></param>
/// <returns></returns>
public bool WriteDO(int add, Box_Sta sta)
{
try
{
Com.TCP.RequestInfo request = new Com.TCP.RequestInfo();
request.StartAddr = _addressOutput[add];//起始地址
request.FunCode = 5;//功能码
request.EquipAddr = equipAddr;
request.CountOrValue = sta.Equals(Box_Sta.On) ? 1 : 0; //值
_client.AddRequest(request);
_client.AddRequest(GetReadDO_Command());
return true;
}
catch (Exception ex)
{
LogUtil.Error("WriteDO", ex);
return false;
}
}
/// <summary>
/// 写入多个DO输出状态(ON/OFF)
/// 写多个线圈,功能码15
/// </summary>
/// <param name="add">起始地址</param>
/// <param name="sta">对应的状态</param>
/// <returns></returns>
public bool WriteDO(int add, Box_Sta[] sta)
{
try
{
Com.TCP.RequestInfo request = new Com.TCP.RequestInfo();
request.StartAddr = _addressOutput[add];//起始地址
request.FunCode = 15;//功能码
request.EquipAddr = equipAddr;
request.CountOrValue = sta.Length; //个数
request.Values = Com.Protocol.Modbus.Register.GetValuesWithMultiMode(GetValues(sta));
_client.AddRequest(request);
_client.AddRequest(GetReadDO_Command());
return true;
}
catch (Exception ex)
{
LogUtil.Error("WriteDO", ex);
return false;
}
}
int[] GetValues(Box_Sta[] sta)
{
int[] tmp = new int[sta.Length];
for (int i = 0; i < sta.Length; i++)
{
tmp[i] = sta[i].Equals(Box_Sta.On) ? 1 : 0;
}
return tmp;
}
/// <summary>
/// 发送命令线程
/// </summary>
private void Send()
{
bool shift = true; //切换
int time = UPLOAD_TIME; //上传时间
while (_loop)
{
Com.TCP.RequestInfo request = null;
if (Upload) //主动上传
{
time += SEND_SLEEP;
if (time >= UPLOAD_TIME)
{
request = GetReadInput_Command();
time = 0;
}
else
{
//2020年6月11日
//buff = GetReadDO_Command();
Thread.Sleep(SEND_SLEEP);
continue;
}
}
else
{
if (shift)
request = GetReadInput_Command();
else
request = GetReadDO_Command();
shift = !shift;
}
_client.AddRequest(request);
Thread.Sleep(SEND_SLEEP);
}
}
/// <summary>
/// 读取输入
/// 数字信号输入,功能码为02,读离散输入
/// 模拟量输入,功能码为04,读输入寄存器
/// </summary>
/// <returns></returns>
private Com.TCP.RequestInfo GetReadInput_Command()
{
Com.TCP.RequestInfo request = new Com.TCP.RequestInfo();
request.StartAddr = _addressInput[0];//起始地址
//功能码
if (_typeInput == IOType.DI)
request.FunCode = 2;
else if (_typeInput == IOType.AI)
request.FunCode = 4;
request.EquipAddr = equipAddr;
request.CountOrValue = _addressInput.Length; //个数
return request;
}
/// <summary>
/// 读取DO,功能码01,读单个线圈
/// </summary>
/// <returns></returns>
private Com.TCP.RequestInfo GetReadDO_Command()
{
return new Com.TCP.RequestInfo()
{
StartAddr = _addressOutput[0],//起始地址
FunCode = 1,//功能码
EquipAddr = equipAddr,
CountOrValue = _addressOutput.Length //个数
};
}
}
}
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace DL.Com
{
public class ComHelper
{
static UdpClient broadcastClient; //广播客户端
static IPEndPoint broadcastEndPoint; //广播远程节点
static byte[] broadcastBuffer; //远程返回数据
/// <summary>
/// 自动获取IP地址,未连接前使用,必须在同一网段
/// </summary>
/// <param name="localIP">本地IP地址</param>
/// <returns></returns>
public static bool AutoIP(string localIP,out string ip)
{
ip = "";
try
{
IPEndPoint local = new IPEndPoint(IPAddress.Parse(localIP), 55654);
broadcastClient = new UdpClient(local);
broadcastBuffer = null;
Thread tTemp = new Thread(new ThreadStart(GetIP));
tTemp.Start();
broadcastEndPoint = new IPEndPoint(IPAddress.Parse("255.255.255.255"), 1024);
byte[] dgram = new byte[] { 0x05, 0x00, 0x07, 0x00, 0x00, 0xC1, 0x59 };
broadcastClient.Send(dgram, dgram.Length, broadcastEndPoint);
Thread.Sleep(1000);
tTemp.Abort();
broadcastClient.Close();
//ErrInfo = "无法访问";
if (broadcastBuffer == null) return false;
if (broadcastBuffer[0] != 0x3B) return false;
byte[] buff = new byte[broadcastBuffer[7]];
Array.Copy(broadcastBuffer, 9, buff, 0, buff.Length);
ip = buff[buff.Length - 12] + "." + buff[buff.Length - 11] + "." + buff[buff.Length - 10] + "." + buff[buff.Length - 9];
//ErrInfo = "OK";
return true;
}
catch (Exception ex)
{
return false;
}
}
/// <summary>
/// 获取目标IP地址
/// </summary>
static void GetIP()
{
broadcastBuffer = broadcastClient.Receive(ref broadcastEndPoint);
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{F85A7412-B5B3-4291-A448-A10564602E1A}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DL.IOModule</RootNamespace>
<AssemblyName>DL.IOModule</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="log4net">
<HintPath>..\..\dll\log4net.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\dll\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="AIOBOX\AIOBOX.cs" />
<Compile Include="CommHelper.cs" />
<Compile Include="HttpHelper.cs" />
<Compile Include="IOState.cs" />
<Compile Include="IOType.cs" />
<Compile Include="JsonHelper.cs" />
<Compile Include="LogUtil.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Protocol\Modbus\CoilRegister.cs" />
<Compile Include="Protocol\Modbus\DataFrame.cs" />
<Compile Include="Protocol\Modbus\DiscreteInputRegister.cs" />
<Compile Include="Protocol\Modbus\HoldingRegister.cs" />
<Compile Include="Protocol\Modbus\InputRegister.cs" />
<Compile Include="Protocol\Modbus\Register.cs" />
<Compile Include="StringHelper.cs" />
<Compile Include="TCP\ModbusTCPMaster.cs" />
<Compile Include="TCP\TcpClient.cs" />
<Compile Include="TCP\TcpServer.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Protocol\Modbus\_system~.ini" />
<None Include="Protocol\_system~.ini" />
<None Include="TCP\_system~.ini" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Common\Common.csproj">
<Project>{43CDD09E-FCF3-4960-A01D-3BBFE9933122}</Project>
<Name>Common</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
\ No newline at end of file \ No newline at end of file
using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DL.Utils
{
public class HttpHelper
{
/// <summary>
/// 检查IP是否合法
/// </summary>
/// <param name="ip"></param>
/// <returns></returns>
public static bool CheckIP(string ip,string name="")
{
//IP合法
string pattern = @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$";
bool rtn = System.Text.RegularExpressions.Regex.IsMatch(ip, pattern);
if (!rtn)
{
LogUtil.Error($"【{name}】非法的IP地址:" + ip);
return false;
}
return true;
}
/// <summary>
/// Ping指定IP
/// </summary>
/// <param name="ip"></param>
/// <returns></returns>
public static bool PingIP(string ip)
{
//Ping服务端
try
{
System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
System.Net.NetworkInformation.PingReply result = ping.Send(ip, 2000);
ping.Dispose();
if (result.Status != System.Net.NetworkInformation.IPStatus.Success)
{
return false;
}
return true;
}
catch (Exception ex)
{
LogUtil.Error($"PingIP{ip}:", ex);
return false;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace DL.IOModule
{
public enum Box_Sta : byte
{
/// <summary>
/// 断开,关闭,低电平
/// </summary>
Off,
/// <summary>
/// 闭合,打开,高电平
/// </summary>
On
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace DL.IOModule
{
/// <summary>
/// IO模块类型
/// </summary>
public enum IOType : byte
{
/// <summary>
/// 数字信号输入
/// </summary>
DI,
/// <summary>
/// 数字信号输出
/// </summary>
DO,
/// <summary>
/// 模拟量输入
/// </summary>
AI,
/// <summary>
/// 模拟量输出
/// </summary>
AO
}
}
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
namespace DL.Utils
{
/// <summary>
/// Json帮助类
/// </summary>
public class JsonHelper
{
/// <summary>
/// 将对象序列化为JSON格式
/// </summary>
/// <param name="o">对象</param>
/// <returns>json字符串</returns>
public static string SerializeObject(object o)
{
string json = JsonConvert.SerializeObject(o);
return json;
}
/// <summary>
/// 解析JSON字符串生成对象实体
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="json">json字符串(eg.{"ID":"112","Name":"石子儿"})</param>
/// <returns>对象实体</returns>
public static T DeserializeJsonToObject<T>(string json) where T : class
{
JsonSerializer serializer = new JsonSerializer();
StringReader sr = new StringReader(json);
object o = serializer.Deserialize(new JsonTextReader(sr), typeof(T));
T t = o as T;
return t;
}
/// <summary>
/// 解析JSON数组生成对象实体集合
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="json">json数组字符串(eg.[{"ID":"112","Name":"石子儿"}])</param>
/// <returns>对象实体集合</returns>
public static List<T> DeserializeJsonToList<T>(string json) where T : class
{
JsonSerializer serializer = new JsonSerializer();
StringReader sr = new StringReader(json);
object o = serializer.Deserialize(new JsonTextReader(sr), typeof(List<T>));
List<T> list = o as List<T>;
return list;
}
/// <summary>
/// 反序列化JSON到给定的匿名对象.
/// </summary>
/// <typeparam name="T">匿名对象类型</typeparam>
/// <param name="json">json字符串</param>
/// <param name="anonymousTypeObject">匿名对象</param>
/// <returns>匿名对象</returns>
public static T DeserializeAnonymousType<T>(string json, T anonymousTypeObject)
{
T t = JsonConvert.DeserializeAnonymousType(json, anonymousTypeObject);
return t;
}
}
///// <summary>
///// 与服务器通信用对象
///// </summary>
//public class Operation
//{
// private string _cid = "";
// public string cid
// {
// get { return _cid; }
// set { _cid = value; }
// }
// public int seq { get; set; }
// public int op { get; set; }
// public int status { get; set; }
// private string _error = "";
// public string error
// {
// get { return _error; }
// set { _error = value; }
// }
// private Dictionary<string, string> _data = new Dictionary<string,string>();
// public Dictionary<string, string> data {
// get { return _data; }
// set { _data = value; }
// }
//}
}
using log4net;
using System;
using System.Reflection;
using System.Drawing;
using log4net.Repository;
using log4net.Config;
using System.IO;
using System.Text;
using System.Collections.Generic;
namespace DL.Utils
{
public class LogUtil
{
static Dictionary<string, ILog> LogMap = new Dictionary<string, ILog>();
public delegate void ShowMsg(string msg);
public static event ShowMsg ShowDebug;
public static event ShowMsg ShowInfo;
public static event ShowMsg ShowWarn;
public static event ShowMsg ShowError;
static readonly ILog defaultLog = LogManager.GetLogger("AIOBOX");
public static void Init()
{
XmlConfigurator.Configure(new FileInfo("log4net.config"));
LogMap.Add("AIOBOX", defaultLog);
}
public static void AddLogMap(string key, ILog log)
{
LogMap.Add(key, log);
}
#region Main log
public static void Debug(string msg, ILog log = null)
{
ShowDebug?.Invoke(msg);
if (log == null)
defaultLog.Debug(msg);
else
log.Debug(msg);
}
public static void Info(string msg, ILog log = null)
{
ShowInfo?.Invoke(msg);
if (log == null)
defaultLog.Info(msg);
else
log.Info(msg);
}
public static void Info(string msg, string logName)
{
ShowInfo?.Invoke(msg);
if (string.IsNullOrEmpty(logName))
defaultLog.Info(msg);
else if (LogMap.ContainsKey(logName) && LogMap[logName] != null)
LogMap[logName].Info(msg);
}
public static void Warn(string msg, ILog log = null)
{
ShowWarn?.Invoke(msg);
if (log == null)
defaultLog.Warn(msg);
else
log.Warn(msg);
}
public static void Error(string msg, Exception exception, ILog log)
{
StringBuilder sb = new StringBuilder(msg + "\r\n");
if (log == null)
{
if (exception == null)
defaultLog.Error(msg);
else
{
defaultLog.Error(msg, exception);
sb.Append(exception.StackTrace);
}
}
else
{
if (exception == null)
log.Error(msg);
else
{
log.Error(msg, exception);
sb.Append(exception.StackTrace);
}
}
ShowError?.Invoke(sb.ToString());
}
public static void Error(string msg, ILog log, Exception exception)
{
StringBuilder sb = new StringBuilder(msg + "\r\n");
if (log == null)
{
if (exception == null)
defaultLog.Error(msg);
else
{
defaultLog.Error(msg, exception);
sb.Append(exception.StackTrace);
}
}
else
{
if (exception == null)
log.Error(msg);
else
{
log.Error(msg, exception);
sb.Append(exception.StackTrace);
}
}
ShowError?.Invoke(sb.ToString());
}
public static void Error(string msg, ILog log)
{
StringBuilder sb = new StringBuilder(msg + "\r\n");
if (log == null)
{
defaultLog.Error(msg);
}
else
{
log.Error(msg);
}
ShowError?.Invoke(sb.ToString());
}
public static void Error(string msg, Exception exception)
{
StringBuilder sb = new StringBuilder(msg + "\r\n");
if (exception == null)
defaultLog.Error(msg);
else
{
defaultLog.Error(msg, exception);
sb.Append(exception.StackTrace);
}
ShowError?.Invoke(sb.ToString());
}
public static void Error(string msg)
{
defaultLog.Error(msg);
ShowError?.Invoke(msg);
}
#endregion
}
}
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("DL.IOModule")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DL.IOModule")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("f85a7412-b5b3-4291-a448-a10564602e1a")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DL.Com.Protocol.Modbus
{
/// <summary>
/// 线圈寄存器:可读可写。
/// 支持的功能码:
/// 0x01:读线圈
/// 0x05:写线圈
/// 0x0F:写多个线圈
/// </summary>
public class CoilRegister : Register
{
public CoilRegister() : base()
{
FunctionCodes.Add(RegisterFunction.Read, 0x01);
FunctionCodes.Add(RegisterFunction.WriteSingle, 0x05);
FunctionCodes.Add(RegisterFunction.WriteMultiple, 0x0F);
}
/// <summary>
/// PLC地址
/// </summary>
public new string PLCAddress
{
get { return $"0{FrameStruct.PDU.Data.Addr.GetIntValue()}"; }
}
/// <summary>
/// 解析写单个线圈
/// </summary>
/// <returns>写入成功</returns>
protected override bool ParseWriteSingle(byte[] respoonse)
{
if (GetResponseResult(respoonse, out byte[] data))
{
//数据部分,发送与接收一致
byte[] senddata = FrameStruct.PDU.Data.ToBytes();
if (data != null && data.Length != senddata.Length)
return false;
for (int i = 0; i < senddata.Length; i++)
{
if (senddata[i] != data[i])
{
return false;
}
}
return true;
}
return false;
}
/// <summary>
/// 解析写多个线圈
/// </summary>
/// <returns>写入成功/returns>
protected override bool ParseWriteMultiple(byte[] response)
{
if (GetResponseResult(response, out byte[] data))
{
byte[] senddata = FrameStruct.PDU.Data.AddrValueToBytes();
if (data != null && data.Length != senddata.Length)
return false;
for (int i = 0; i < senddata.Length; i++)
{
if (senddata[i] != data[i])
{
return false;
}
}
return true;
}
return false;
}
protected override void SetParamPDU(CmdByte cmd)
{
if (cmd.Function.Equals(RegisterFunction.WriteSingle))
{
SetPDU(cmd.Function, cmd.StartAddr, cmd.Count.Equals(new Byte2 { ByteH = 0x00, ByteL = 0x00 }) ? cmd.Count : new Byte2 { ByteH = 0xFF, ByteL = 0x00 }, cmd.ByteLength, cmd.ValuesOfMultiple);
}
else if (cmd.Function.Equals(RegisterFunction.WriteMultiple))
{
SetPDU(cmd.Function, cmd.StartAddr, cmd.Count, cmd.ByteLength, cmd.ValuesOfMultiple);
}
else
{
SetPDU(RegisterFunction.Read, cmd.StartAddr, cmd.Count);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DL.Com.Protocol.Modbus
{
/// <summary>
/// 数据帧:报文头+帧结构
/// </summary>
public class DataFrame
{
/// <summary>
/// 报文头
/// </summary>
public MBAP MBAP;
/// <summary>
/// 帧结构
/// </summary>
public PDU PDU;
public DataFrame()
{
MBAP = new MBAP();
PDU = new PDU();
}
/// <summary>
/// 设置帧数据
/// </summary>
/// <param name="functionCode">功能码</param>
/// <param name="addr">开始地址</param>
/// <param name="value">数量</param>
/// <param name="bytelenght">字节长度,写多个线圈/寄存器使用</param>
/// <param name="valueofmulti">写入的值,写多个线圈/寄存器使用</param>
public void SetPDU(byte functionCode, ushort addr, ushort value, byte bytelenght = 0, byte[] valueofmulti = null)
{
PDU.SetPDUFunctionCode(functionCode);
PDU.SetPDUData(addr, value, bytelenght, valueofmulti);
MBAP.SetDataLength(PDU.GetLength());
}
/// <summary>
/// 设置帧数据
/// </summary>
/// <param name="functionCode">功能码</param>
/// <param name="addr">开始地址</param>
/// <param name="value">数量</param>
/// <param name="bytelenght">字节长度,写多个线圈/寄存器使用</param>
/// <param name="valueofmulti">写入的值,写多个线圈/寄存器使用</param>
public void SetPDU(byte functionCode, Byte2 addr, Byte2 value, byte bytelenght = 0x00, byte[] valueofmulti = null)
{
PDU.SetPDUFunctionCode(functionCode);
PDU.SetPDUData(addr, value, bytelenght, valueofmulti);
MBAP.SetDataLength(PDU.GetLength());
}
/// <summary>
/// 设置报文头
/// </summary>
public void SetMBAP(ushort serialnum, byte equipAddr, ushort protocolid = 0)
{
MBAP.SetSerialNum(serialnum);
MBAP.SetEquipAddr(equipAddr);
MBAP.SetProtocolId(protocolid);
}
/// <summary>
/// 设置报文头
/// </summary>
public void SetMBAP(Byte2 serialnum, byte equipAddr, ushort protocolid = 0)
{
MBAP.SetSerialNum(serialnum);
MBAP.SetEquipAddr(equipAddr);
MBAP.SetProtocolId(protocolid);
}
/// <summary>
/// 数据帧字节数据
/// </summary>
/// <returns></returns>
public byte[] ToBytes()
{
List<byte> tmp = new List<byte>();
tmp.AddRange(MBAP.ToBytes());
tmp.AddRange(PDU.ToBytes());
return tmp.ToArray();
}
public byte[] ToMbapFuncCodeBytes()
{
List<byte> tmp = new List<byte>();
tmp.AddRange(MBAP.ToBytes());
tmp.Add(PDU.FuncCode);
return tmp.ToArray();
}
}
/// <summary>
/// 报文头
/// </summary>
public class MBAP
{
/// <summary>
/// 报文序列号,事务处理标识符
/// 长度:2字节
/// </summary>
public Byte2 SerialNum;
/// <summary>
/// 协议标识符
/// 0000标识ModbusTCP协议
/// 长度:2字节
/// </summary>
public Byte2 ProtocolId;
/// <summary>
/// 接下来的数据长度
/// 长度:2字节
/// </summary>
public Byte2 DataLength;
/// <summary>
/// 设备地址
/// 长度:1字节
/// </summary>
public byte EquipAddr;
public MBAP()
{
SerialNum = new Byte2();
ProtocolId = new Byte2();
DataLength = new Byte2();
}
public void SetData(byte[] data)
{
if (data.Length > 7)
{
SerialNum.Set(data[0], data[1]);
ProtocolId.Set(data[2], data[3]);
DataLength.Set(data[4], data[5]);
EquipAddr = data[6];
}
}
public void SetSerialNum(UInt16 serialnum)
{
SerialNum.SetByInt(serialnum);
}
public void SetSerialNum(byte Hi, byte Low)
{
SerialNum.Set(Hi, Low);
}
public void SetSerialNum(Byte2 stru2Byte)
{
SerialNum.Set(stru2Byte);
}
/// <summary>
/// 设置协议ID,默认TCP协议
/// </summary>
/// <param name="protocolid"></param>
public void SetProtocolId(UInt16 protocolid = 0)
{
ProtocolId.SetByInt(protocolid);
}
/// <summary>
/// 设置协议ID,默认TCP协议
/// </summary>
/// <param name="Hi"></param>
/// <param name="Low"></param>
public void SetProtocolId(byte Hi = 0x00, byte Low = 0x00)
{
ProtocolId.Set(Hi, Low);
}
public void SetProtocolId(Byte2 stru2Byte)
{
ProtocolId.Set(stru2Byte);
}
/// <summary>
/// 设置协议地址
/// </summary>
/// <param name="equipAddr"></param>
public void SetEquipAddr(byte equipAddr)
{
EquipAddr = equipAddr;
}
/// <summary>
/// 设置接下来的数据长度
/// </summary>
/// <param name="datalength">PDU里的数据长度</param>
public void SetDataLength(ushort datalength)
{
DataLength.SetByInt((ushort)(datalength+1));
}
/// <summary>
/// 设置接下来的数据长度
/// </summary>
/// <param name="Hi"></param>
/// <param name="Low"></param>
public void SetDataLength(byte Hi, byte Low)
{
DataLength.Set(Hi, Low);
}
public override bool Equals(object obj)
{
MBAP cMBAP = obj as MBAP;
if (cMBAP == null)
return false;
if (cMBAP.SerialNum.Equals(this.SerialNum) &&
cMBAP.ProtocolId.Equals(this.ProtocolId) &&
cMBAP.EquipAddr.Equals(this.EquipAddr))
return true;
else
return false;
}
/// <summary>
/// 报文头字节数据
/// </summary>
/// <returns></returns>
public byte[] ToBytes()
{
List<byte> tmp = new List<byte>();
tmp.AddRange(SerialNum.ToBytes());
tmp.AddRange(ProtocolId.ToBytes());
tmp.AddRange(DataLength.ToBytes());
tmp.Add(EquipAddr);
return tmp.ToArray();
}
}
/// <summary>
/// 数据帧
/// </summary>
public class PDU
{
/// <summary>
/// 功能码
/// </summary>
public byte FuncCode;
/// <summary>
/// 数据
/// </summary>
public DataInPDU Data;
public PDU()
{
Data = new DataInPDU();
}
/// <summary>
/// 设置帧结构功能码
/// </summary>
/// <param name="funcCode">功能码</param>
public void SetPDUFunctionCode(byte funcCode)
{
FuncCode = funcCode;
}
public void SetPDUData(ushort addr, ushort value, byte bytelenght = 0, byte[] valueofmulti = null)
{
Data.SetData(addr, value, bytelenght, valueofmulti);
}
public void SetPDUData(Byte2 addr, Byte2 value, byte bytelenght = 0x00, byte[] valueofmulti = null)
{
Data.SetData(addr, value, bytelenght, valueofmulti);
}
/// <summary>
/// 帧结构的数据长度
/// </summary>
/// <returns></returns>
public ushort GetLength()
{
return (ushort)(Data.Length() + 1);
}
public byte[] ToBytes()
{
List<byte> tmp = new List<byte>();
tmp.Add(FuncCode);
tmp.AddRange(Data.ToBytes());
return tmp.ToArray();
}
}
public class DataInPDU
{
/// <summary>
/// 起始地址/寄存器地址
/// </summary>
public Byte2 Addr;
/// <summary>
/// 数量/值
/// </summary>
public Byte2 Value;
/// <summary>
/// 字节长度,写多个线圈/保持寄存器时使用
/// </summary>
public byte ByteLength;
/// <summary>
/// 输出值/寄存器值,写多个线圈/保持寄存器时使用
/// </summary>
public List<byte> ValueOfMulti;
public DataInPDU()
{
Addr = new Byte2();
Value = new Byte2();
ValueOfMulti = new List<byte>();
}
public void SetData(ushort addr, ushort value, byte bytelenght = 0, byte[] valueofmulti = null)
{
Addr.SetByInt(addr);
Value.SetByInt(value);
ByteLength = bytelenght;
ValueOfMulti.Clear();
if (valueofmulti != null)
foreach (var item in valueofmulti)
{
ValueOfMulti.Add(item);
}
}
public void SetData(Byte2 addr, Byte2 value, byte bytelenght = 0x00, byte[] valueofmulti = null)
{
Addr.Set(addr);
Value.Set(value);
ByteLength = bytelenght;
ValueOfMulti.Clear();
if (valueofmulti != null)
foreach (var item in valueofmulti)
{
ValueOfMulti.Add(item);
}
}
public byte[] ToBytes()
{
List<byte> tmp = new List<byte>();
tmp.AddRange(Addr.ToBytes());
tmp.AddRange(Value.ToBytes());
if (ByteLength != 0)
{
tmp.Add(ByteLength);
foreach (var item in ValueOfMulti)
{
tmp.Add(item);
}
}
return tmp.ToArray();
}
public byte[] AddrValueToBytes()
{
List<byte> tmp = new List<byte>();
tmp.AddRange(Addr.ToBytes());
tmp.AddRange(Value.ToBytes());
return tmp.ToArray();
}
public int Length()
{
List<byte> tmp = new List<byte>();
tmp.AddRange(Addr.ToBytes());
tmp.AddRange(Value.ToBytes());
if (ByteLength != 0)
{
tmp.Add(ByteLength);
foreach (var item in ValueOfMulti)
{
tmp.Add(item);
}
}
return tmp.Count;
}
}
/// <summary>
/// 两字节组成的值
/// </summary>
public struct Byte2
{
public byte ByteH { get; set; }
public byte ByteL { get; set; }
public static Byte2 GetStru2Byte(ushort val)
{
return new Byte2
{
ByteH = (byte)((val >> 8) & 0xff),
ByteL = (byte)((val & 0xff))
};
}
public static ushort GetUInt16(byte H,byte L)
{
return (ushort)(((H & 0xff) << 8) | (L & 0xff));
}
public static short GetInt16(byte H, byte L)
{
return (short)((H << 8) | (L & 0xff));
}
public static int GetInt32(byte H, byte L)
{
return ((H << 8) | (L & 0xff));
}
public static uint GetUInt32(byte H, byte L)
{
return (uint)(((H & 0xff) << 8) | (L & 0xff));
}
public void SetByInt(ushort val)
{
ByteH = (byte)((val >> 8) & 0xff);
ByteL = (byte)((val & 0xff));
}
public void Set(byte High, byte Low)
{
ByteH = High;
ByteL = Low;
}
public void Set(Byte2 stru2Byte)
{
ByteH = stru2Byte.ByteH;
ByteL = stru2Byte.ByteL;
}
public ushort GetIntValue()
{
return (ushort)(((ByteH & 0xff) << 8) | (ByteL & 0xff));
}
public override string ToString()
{
return $"{ByteH.ToString("x2")} {ByteL.ToString("x2")}";
}
public override bool Equals(object obj)
{
Byte2 stru2Byte = (Byte2)obj;
return ByteH.Equals(stru2Byte.ByteH) && ByteL.Equals(stru2Byte.ByteL);
}
public byte[] ToBytes()
{
return new byte[] { ByteH, ByteL };
}
}
/// <summary>
/// 四字节组成的值
/// </summary>
public struct Byte4
{
public byte ByteH1 { get; set; }
public byte ByteH2 { get; set; }
public byte ByteL1 { get; set; }
public byte ByteL2 { get; set; }
public static Byte4 GetStru2Byte(int val)
{
return new Byte4
{
ByteH1 = (byte)((val >> 24) & 0xff),
ByteH2 = (byte)((val >> 16) & 0xff),
ByteL1 = (byte)((val >> 8) & 0xff),
ByteL2 = (byte)((val & 0xff))
};
}
public void SetByInt(uint val)
{
ByteH1 = (byte)((val >> 24) & 0xff);
ByteH2 = (byte)((val >> 16) & 0xff);
ByteL1 = (byte)((val >> 8) & 0xff);
ByteL2 = (byte)((val & 0xff));
}
public void Set(Byte4 stru4Byte)
{
ByteH1 = stru4Byte.ByteH1;
ByteH2 = stru4Byte.ByteH2;
ByteL1 = stru4Byte.ByteL1;
ByteL2 = stru4Byte.ByteL2;
}
public static uint GetUInt32(byte h1,byte h2,byte l1,byte l2)
{
return (uint)(((h1 & 0xff) << 24) | ((h2 & 0xff) << 16) | ((l1 & 0xff) << 8) | (l2 & 0xff));
}
public static int GetInt32(byte h1, byte h2, byte l1, byte l2)
{
return (int)((h1 << 24) | ((h2 & 0xff) << 16) | ((l1 & 0xff) << 8) | (l2 & 0xff));
}
/// <summary>
/// 大终端转float
/// </summary>
/// <param name="h1"></param>
/// <param name="h2"></param>
/// <param name="l1"></param>
/// <param name="l2"></param>
/// <returns></returns>
public static float GetFloat(byte h1, byte h2, byte l1, byte l2)
{
byte[] tmp = new byte[4] { h1,h2,l1,l2};
return (float)(GetInt32(h1, h2, l1, l2));
//float f = 0;
//byte[] x = tmp;
//byte i;
//unsafe
//{
// void* pf;
// fixed(byte* pb = x)
// {
// pf = &f;
// for (i = 0; i < tmp.Length; i++)
// {
// *((byte*)pf + i) = *(pb+i);
// }
// }
//}
//return f;
}
public uint GetIntValue()
{
return (uint)(((ByteH1 & 0xff) << 24) | ((ByteH2 & 0xff) << 16) | ((ByteL1 & 0xff) << 8) | (ByteL2 & 0xff));
}
public override string ToString()
{
return $"{ByteH1.ToString("x2")} {ByteH2.ToString("x2")} {ByteL1.ToString("x2")} {ByteL2.ToString("x2")}";
}
public override bool Equals(object obj)
{
Byte4 stru4Byte = (Byte4)obj;
return ByteH1.Equals(stru4Byte.ByteH1) && ByteH2.Equals(stru4Byte.ByteH2) && ByteL1.Equals(stru4Byte.ByteL1) && ByteL2.Equals(stru4Byte.ByteL2);
}
public byte[] ToBytes()
{
return new byte[] { ByteH1, ByteH2, ByteL1, ByteL2 };
}
}
public class ResponseData
{
public MBAP MBAP { get; set; }
public byte FuncCode { get; set; }
public byte[] OtherData { get; set; }
public ResponseData()
{
MBAP = new MBAP();
}
public void Set(byte[] data)
{
if (data == null)
return;
MBAP.SetData(data);
FuncCode = data[7];
OtherData = new byte[data.Length - 8];
Array.Copy(data, 8, OtherData, 0, data.Length - 8);
}
public byte[] ToBytes()
{
List<byte> vs = new List<byte>();
vs.AddRange(MBAP.ToBytes());
vs.Add(FuncCode);
vs.AddRange(OtherData);
return vs.ToArray();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DL.Com.Protocol.Modbus
{
/// <summary>
/// 离散输入寄存器
/// 功能码0x02
/// </summary>
public class DiscreteInputRegister:Register
{
/// <summary>
/// 离散输入寄存器
/// 功能码0x02
/// </summary>
public DiscreteInputRegister() :base()
{
FunctionCodes.Add(RegisterFunction.Read, 0x02);
}
/// <summary>
/// PLC地址
/// </summary>
public new string PLCAddress
{
get { return $"1{FrameStruct.PDU.Data.Addr.GetIntValue()}"; }
}
protected override bool ParseWriteMultiple(byte[] response)
{
throw new NotImplementedException();
}
protected override bool ParseWriteSingle(byte[] response)
{
throw new NotImplementedException();
}
protected override void SetParamPDU(CmdByte cmdByte)
{
SetPDU(RegisterFunction.Read, cmdByte.StartAddr, cmdByte.Count);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DL.Com.Protocol.Modbus
{
/// <summary>
/// 保持寄存器
/// 0x03
/// </summary>
public class HoldingRegister : Register
{
public HoldingRegister() : base()
{
FunctionCodes.Add(RegisterFunction.Read, 0x03);
FunctionCodes.Add(RegisterFunction.WriteSingle, 0x06);
FunctionCodes.Add(RegisterFunction.WriteMultiple, 0x10);
}
/// <summary>
/// PLC地址
/// </summary>
public new string PLCAddress
{
get { return $"4{FrameStruct.PDU.Data.Addr.GetIntValue()}"; }
}
public override byte[] GetRequestBytes(RegisterFunction func, ushort startAddr, ushort countOrValue,byte equipAddr=1, ushort[] ValuesOfMultiple = null)
{
CmdByte cmdByte = new CmdByte();
cmdByte.StartAddr = Byte2.GetStru2Byte(startAddr);
cmdByte.Function = func;
cmdByte.Count = Byte2.GetStru2Byte(countOrValue);
if (func.Equals(RegisterFunction.WriteMultiple))
{
if (ValuesOfMultiple == null)
return null;
List<byte> values = new List<byte>();
foreach (var item in ValuesOfMultiple)
{
values.AddRange(Byte2.GetStru2Byte(item).ToBytes());
}
cmdByte.ByteLength = (byte)(countOrValue * 2);
cmdByte.ValuesOfMultiple = values.ToArray();
}
SetMBAP(_serialnum, equipAddr);
SetParamPDU(cmdByte);
return DataFrame;
}
protected override void SetParamPDU(CmdByte cmdByte)
{
if (cmdByte.Function.Equals(RegisterFunction.WriteSingle))
{
SetPDU(cmdByte.Function, cmdByte.StartAddr, cmdByte.Count, cmdByte.ByteLength, cmdByte.ValuesOfMultiple);
}
else if (cmdByte.Function.Equals(RegisterFunction.WriteMultiple))
{
SetPDU(cmdByte.Function, cmdByte.StartAddr, cmdByte.Count, cmdByte.ByteLength, cmdByte.ValuesOfMultiple);
}
else
SetPDU(RegisterFunction.Read, cmdByte.StartAddr, cmdByte.Count);
}
protected override bool ParseWriteSingle(byte[] response)
{
if (GetResponseResult(response, out byte[] data))
{
//数据部分,发送与接收一致
byte[] senddata = FrameStruct.PDU.Data.ToBytes();
if (data != null && data.Length != senddata.Length)
return false;
for (int i = 0; i < senddata.Length; i++)
{
if (senddata[i] != data[i])
{
return false;
}
}
return true;
}
return false;
}
protected override bool ParseWriteMultiple(byte[] response)
{
if (GetResponseResult(response, out byte[] data))
{
byte[] senddata = FrameStruct.PDU.Data.AddrValueToBytes();
if (data != null && data.Length != senddata.Length)
return false;
for (int i = 0; i < senddata.Length; i++)
{
if (senddata[i] != data[i])
{
return false;
}
}
return true;
}
return false;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DL.Com.Protocol.Modbus
{
/// <summary>
/// 输入寄存器
/// 支持的功能码0x04
/// </summary>
public class InputRegister : Register
{
public InputRegister() : base()
{
FunctionCodes.Add(RegisterFunction.Read, 0x04);
}
/// <summary>
/// PLC地址
/// </summary>
public new string PLCAddress
{
get { return $"3{FrameStruct.PDU.Data.Addr.GetIntValue()}"; }
}
protected override bool ParseWriteMultiple(byte[] response)
{
throw new NotImplementedException();
}
protected override bool ParseWriteSingle(byte[] response)
{
throw new NotImplementedException();
}
protected override void SetParamPDU(CmdByte cmdByte)
{
SetPDU(RegisterFunction.Read, cmdByte.StartAddr, cmdByte.Count);
}
}
}
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using DL.Com;
using DL.Utils;
namespace DL.Com.Protocol.Modbus
{
/// <summary>
/// 寄存器
/// </summary>
public abstract class Register
{
public delegate void StatusChangedEventHandler(StatusChangedEventArgs statusChangedEventArgs);
public event StatusChangedEventHandler StatusChanged;
protected static log4net.ILog log;
protected static ushort _serialnum = 0;
public Register(string logname = "logModbus")
{
log = log4net.LogManager.GetLogger(logname);
FunctionCodes = new Dictionary<RegisterFunction, byte>();
FrameStruct = new DataFrame();
}
/// <summary>
/// 功能码
/// </summary>
public Dictionary<RegisterFunction, byte> FunctionCodes { get; set; }
/// <summary>
/// 帧结构
/// </summary>
public DataFrame FrameStruct { get; protected set; }
/// <summary>
/// 数据帧--字节数据
/// </summary>
public byte[] DataFrame { get { return FrameStruct.ToBytes(); } }
/// <summary>
/// PLC地址
/// </summary>
public string PLCAddress { get; }
/// <summary>
/// 根据命令设置PDU参数
/// </summary>
/// <param name="cmdByte"></param>
/// <returns></returns>
protected abstract void SetParamPDU(CmdByte cmdByte);
/// <summary>
/// 设置MBAP报文头
/// </summary>
/// <param name="serialnum">事务处理标识,即报文序列号</param>
/// <param name="equipAddr">单元标识符,即设备地址</param>
protected void SetMBAP(ushort serialnum, byte equipAddr)
{
FrameStruct.SetMBAP(serialnum, equipAddr);
_serialnum++;
if (_serialnum >= ushort.MaxValue)
{
_serialnum = 0;
}
}
/// <summary>
/// 设置帧结构
/// </summary>
/// <param name="funcStr">功能</param>
/// <param name="addr">开始地址</param>
/// <param name="value">数量/值</param>
/// <param name="bytelenght">字节长度,写多个线圈/寄存器使用</param>
/// <param name="valueofmulti">写入的值,写多个线圈/寄存器使用</param>
protected void SetPDU(RegisterFunction func, Byte2 addr, Byte2 value, byte bytelenght = 0x00, byte[] valueofmulti = null)
{
FrameStruct.SetPDU(FunctionCodes[func], addr, value, bytelenght, valueofmulti);
}
/// <summary>
/// 检查响应的MBAP+功能码是否与请求一致
/// </summary>
/// <param name="data">响应的数据</param>
/// <returns>true:请求与返回对应</returns>
private bool CheckResponse(byte[] data, bool ignoreSerialNum = false)
{
if (data != null && data.Length > 8)
{
if (FrameStruct.MBAP.SerialNum.ByteH.Equals(data[0]) &&
FrameStruct.MBAP.SerialNum.ByteL.Equals(data[1]) &&
FrameStruct.MBAP.ProtocolId.ByteH.Equals(data[2]) &&
FrameStruct.MBAP.ProtocolId.ByteL.Equals(data[3]) &&
FrameStruct.MBAP.EquipAddr.Equals(data[6]) &&
FrameStruct.PDU.FuncCode.Equals(data[7])
)
{
return true;
}
if (ignoreSerialNum)
{
if (
FrameStruct.MBAP.ProtocolId.ByteH.Equals(data[2]) &&
FrameStruct.MBAP.ProtocolId.ByteL.Equals(data[3]) &&
FrameStruct.MBAP.EquipAddr.Equals(data[6]) &&
FrameStruct.PDU.FuncCode.Equals(data[7])
)
{
return true;
}
}
}
return false;
}
/// <summary>
/// 获取响应数据的结果,并返回响应的
/// </summary>
/// <param name="data">响应的数据</param>
/// <returns>true:响应成功</returns>
protected bool GetResponseResult(byte[] response, out byte[] data, bool ignoreSerial = false)
{
if (CheckResponse(response, ignoreSerial))
{
data = new byte[response.Length - 8];
Array.Copy(response, 8, data, 0, response.Length - 8);
return true;
}
if (response != null && response.Length >= 8)
{
data = new byte[] { response[7] };
if ((data[0] & 0x80) == 0x80)
{
LogUtil.Error($"从站异常响应[{StringHelper.ToHexString(data[0])}],响应数据为[{StringHelper.ToHexString(response)}]", log);
}
return false;
}
data = new byte[] { 0x00 };
return false;
}
/// <summary>
/// 解析读操作的响应数据
/// </summary>
/// <param name="response">响应的字节数据</param>
/// <param name="data"></param>
/// <param name="ignoreserial">忽略请求编号</param>
/// <returns>true:读取成功</returns>
protected virtual bool ParseRead(byte[] response, out byte[] data, bool ignoreserial = false)
{
data = null;
if (GetResponseResult(response, out byte[] data1, ignoreserial))
{
int len = data1[0];
data = new byte[len];
Array.Copy(data1, 1, data, 0, len);
return true;
}
return false;
}
/// <summary>
/// 解析写单个操作的响应数据
/// </summary>
/// <param name="response">响应的字节数据</param>
/// <returns>true:写入单个操作成功</returns>
protected abstract bool ParseWriteSingle(byte[] response);
/// <summary>
/// 解析写多个操作的响应数据
/// </summary>
/// <param name="response">响应的字节数据</param>
/// <returns>true:写多单个操作成功</returns>
protected abstract bool ParseWriteMultiple(byte[] response);
/// <summary>
/// 获取响应的结果
/// </summary>
/// <param name="function"></param>
/// <param name="response"></param>
/// <param name="data"></param>
/// <returns>解析</returns>
public bool GetResult(RegisterFunction function, byte[] response, out byte[] data)
{
bool rtn = false;
data = null;
switch (function)
{
case RegisterFunction.Read:
rtn = ParseRead(response, out data);
break;
case RegisterFunction.WriteSingle:
rtn = ParseWriteSingle(response);
break;
case RegisterFunction.WriteMultiple:
rtn = ParseWriteMultiple(response);
break;
default:
rtn = ParseRead(response, out data);
break;
}
return rtn;
}
public bool GetReadReault(byte[] response, out byte[] data)
{
bool rtn = ParseRead(response, out data, true);
return rtn;
}
/// <summary>
/// 分离多个反馈字节
/// </summary>
/// <param name="data"></param>
/// <returns>《功能码,响应的数据》</returns>
public static List<byte[]> SplitResponse(byte[] data)
{
List<byte[]> rtn = new List<byte[]>();
List<byte> tmpdata = new List<byte>();
tmpdata.AddRange(data);
while (tmpdata.Count >= 8)
{
if (ParseHeader(tmpdata.ToArray(), out byte func, out int len))
{
byte[] tmp = new byte[len + 6];
Array.Copy(tmpdata.ToArray(), 0, tmp, 0, len + 6);
rtn.Add(tmp);
tmpdata.RemoveRange(0, tmp.Length);
}
}
return rtn;
}
/// <summary>
/// 解析头
/// </summary>
/// <param name="header"></param>
/// <param name="func">功能码</param>
/// <param name="len">长度</param>
/// <returns>解析成功</returns>
public static bool ParseHeader(byte[] header, out byte func, out int len)
{
func = 0;
len = 0;
if (header != null && header.Length >= 8)
{
func = header[7];
len = Byte2.GetInt32(header[4], header[5]);
return true;
}
return false;
}
/// <summary>
/// 写入多个值时,将写入的值转换为发送的数组
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static int[] GetValuesWithMultiMode(int[] data)
{
int mod = data.Length % 8;
List<int> tmp = new List<int>();
int t = 0;
for (int i = 0; i < data.Length; i++)
{
if ((i + 1) % 8 == 0)
{
t += data[i] * (int)Math.Pow(2, data[i]);
tmp.Add(t);
t = 0;
}
else
{
t += data[i] * (int)Math.Pow(2, data[i]);
}
}
if (mod != 0)
tmp.Add(t);
return tmp.ToArray();
}
/// <summary>
/// 设置并获取请求字节数组
/// </summary>
/// <param name="func"></param>
/// <param name="startAddr"></param>
/// <param name="countOrValue"></param>
/// <param name="ValuesOfMultiple"></param>
/// <returns></returns>
public virtual byte[] GetRequestBytes(RegisterFunction func, ushort startAddr, ushort countOrValue, byte equipAddr = 1, ushort[] ValuesOfMultiple = null)
{
CmdByte cmdByte = new CmdByte();
cmdByte.StartAddr = Byte2.GetStru2Byte(startAddr);
cmdByte.Function = func;
cmdByte.Count = Byte2.GetStru2Byte(countOrValue);
if (func.Equals(RegisterFunction.WriteMultiple))
{
if (ValuesOfMultiple == null)
return null;
List<byte> values = new List<byte>();
foreach (var item in ValuesOfMultiple)
{
values.Add((byte)item);
}
cmdByte.ByteLength = (byte)(countOrValue % 8 == 0 ? countOrValue / 8 : countOrValue / 8 + 1);
cmdByte.ValuesOfMultiple = values.ToArray();
}
SetMBAP(_serialnum, equipAddr);
SetParamPDU(cmdByte);
return DataFrame;
}
}
public class StatusChangedEventArgs : EventArgs
{
public Dictionary<int, byte> ChangedIdxAndValue { get; set; }
public byte[] Data;
public bool Init { get; set; }
public StatusChangedEventArgs()
{
ChangedIdxAndValue = new Dictionary<int, byte>();
}
}
public class CmdByte
{
public RegisterFunction Function { get; set; }
public Byte2 StartAddr { get; set; }
public Byte2 Count { get; set; }
public byte ByteLength { get; set; }
public byte[] ValuesOfMultiple { get; set; }
string ToHexString(byte[] data)
{
if (data == null)
return "";
StringBuilder stringBuilder = new StringBuilder();
foreach (var item in data)
{
stringBuilder.Append(item.ToString("x2"));
stringBuilder.Append(" ");
}
return stringBuilder.ToString().Trim();
}
public override string ToString()
{
return $"[Function={Function.ToString()},StartAddr={StartAddr},Count/Value={Count},ByteLength={ByteLength},ValuesOfMultiple={ToHexString(ValuesOfMultiple)}]";
}
}
/// <summary>
/// 寄存器功能
/// </summary>
public enum RegisterFunction
{
/// <summary>
/// 读
/// </summary>
Read,
/// <summary>
/// 写单个
/// </summary>
WriteSingle,
/// <summary>
/// 写多个
/// </summary>
WriteMultiple,
}
/// <summary>
/// 寄存器类型
/// </summary>
public enum RegisterType
{
/// <summary>
/// 线圈,支持的功能码为 0x01,0x05,0x0f
/// </summary>
CoilSatus,
/// <summary>
/// 离散输入,支持的功能码为 0x02
/// </summary>
InputStatus,
/// <summary>
/// 输入寄存器,支持的功能码为 0x04
/// </summary>
InputRegister,
/// <summary>
/// 保持寄存器,支持的功能码为 0x03,0x06,0x10
/// </summary>
HoldingRegister,
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DL.Utils
{
public class StringHelper
{
/// <summary>
/// 字节转十六进制字符串
/// </summary>
/// <param name="buff"></param>
/// <returns></returns>
public static string ToHexString(byte[] buff)
{
StringBuilder sb = new StringBuilder("");
if (buff == null || buff.Length<1) return sb.ToString();
for (int i = 0; i < buff.Length; i++)
{
sb.Append(buff[i].ToString("X2"));
sb.Append(" ");
}
sb.Remove(sb.Length - 1, 1);
return sb.ToString();
}
public static string ToBinaryString(byte[] data)
{
StringBuilder stringBuilder = new StringBuilder("");
if (data == null || data.Length < 1) return stringBuilder.ToString();
stringBuilder.Append("【");
foreach (var item in data)
{
stringBuilder.Append(Convert.ToString(item, 2).PadLeft(8, '0'));
stringBuilder.Append(" ");
}
stringBuilder.Remove(stringBuilder.Length - 1, 1);
stringBuilder.Append("】");
return stringBuilder.ToString();
}
public static string ToHexString(byte data)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("【");
stringBuilder.Append(data.ToString("x2"));
stringBuilder.Append("】");
return stringBuilder.ToString();
}
public static byte[] StrToHexByte(string hexString)
{
hexString = hexString.Replace(" ", "");
if ((hexString.Length % 2) != 0)
hexString += " ";
byte[] returnBytes = new byte[hexString.Length / 2];
for (int i = 0; i < returnBytes.Length; i++)
{
returnBytes[i]=Convert.ToByte(hexString.Substring(i*2,2),16);
}
return returnBytes;
}
/// <summary>
/// 获取类的属性名及其值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <returns></returns>
public static string GetPropertiesStr<T>(T t)
{
StringBuilder sb = new StringBuilder("");
if (t == null)
{
return sb.ToString();
}
System.Reflection.PropertyInfo[] properties = t.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
if (properties.Length <= 0)
{
return sb.ToString();
}
sb.Append("{");
foreach (System.Reflection.PropertyInfo property in properties)
{
string name = property.Name;
object value = property.GetValue(t, null);
if (property.PropertyType.IsValueType || property.PropertyType.Name.StartsWith("String"))
{
sb.Append($"{name}:{value},");
}
else if(property.PropertyType.IsGenericType)
{
var listVal = property.GetValue(t, null) as IEnumerable<object>;
if (listVal == null) continue;
sb.Append("[");
foreach (var item1 in listVal)
{
sb.Append(GetPropertiesStr(item1));
}
sb.Append("]");
}
else if(property.PropertyType.IsArray)
{
var listVal = property.GetValue(t, null) as IEnumerable<object>;
if (listVal == null) continue;
sb.Append("[");
foreach (var item1 in listVal)
{
sb.Append(GetPropertiesStr(item1));
}
sb.Append("]");
}
else
{
sb.Append(GetPropertiesStr(value));
}
}
sb.Append("}");
return sb.ToString();
}
}
}
using DL.Com.Protocol.Modbus;
using DL.Utils;
using log4net;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Threading;
namespace DL.Com.TCP
{
public class ModbusTCPMaster
{
List<Register> registers = new List<Register>() {
new CoilRegister(),new DiscreteInputRegister(),new HoldingRegister(),
new InputRegister()
};
public static List<string> Functions = new List<string>() {
"01 Read Coils","02 Read Discrete Inputs","03 Read Holding Registers",
"04 Read Input Registers","05 WriteSingle Coil","06 Write Single Register",
"0F Write Multiple Coils","10 Write Multiple Registers"
};
TcpClient tcpClient = new TcpClient();
Thread thread;
public delegate void ConnectionChangedHandler(string ip, int port, bool onOff);
public delegate void ReceiveDataHandler(string ip, int port, RequestInfo requestInfo, byte[] data);
public event ConnectionChangedHandler ConnectionChanged;
public event ReceiveDataHandler ReceiveData;
public bool IsAutoReconnect = false;
public int TryTimes = 5;
public string IP { get; private set; }
public int Port { get; private set; }
bool online = false;
public bool Online
{
get { return online; }
private set
{
if (online != value)
{
online = value;
ConnectionChanged?.Invoke(IP, Port, value);
}
}
}
bool start = false;
public ModbusTCPMaster()
{
start = true;
thread = new Thread(sendQueueRequest);
thread.IsBackground = true;
thread.Start();
}
~ModbusTCPMaster()
{
start = false;
}
object locsend = new object();
private const int SEND_SLEEP = 50; //每条命令发送的间隔
void sendQueueRequest()
{
while (start)
{
if (Monitor.TryEnter(locsend))
{
try
{
Online = tcpClient.IsConnected();
if (!Online)
{
if (IsAutoReconnect)
{
tcpClient.Connect(IP, Port, ReceiveMessage);
Thread.Sleep(1000);
RequestInfo requestInfo = GetPeek();
if (requestInfo != null && requestInfo.Requested)
{
requestInfo.SetRequestState(false);
LogUtil.Error($"Disconnect 重置请求状态{requestInfo}");
continue;
}
}
}
else
{
SendRequest();
}
}
catch (Exception ex)
{
LogUtil.Error($"sendQueueRequest出错", ex);
}
finally
{
Monitor.Exit(locsend);
}
}
}
}
/// <summary>
/// 请求队列
/// </summary>
ConcurrentQueue<RequestInfo> requestInfos = new ConcurrentQueue<RequestInfo>();
public void Connect(string ip, int port)
{
IP = ip;
Port = port;
tcpClient.Connect(ip, port, ReceiveMessage);
Thread.Sleep(1000);
IsAutoReconnect = true;
}
public void Close()
{
tcpClient.Close();
}
/// <summary>
/// 添加请求
/// </summary>
/// <param name="requestInfo">请求信息</param>
public void AddRequest(RequestInfo requestInfo)
{
EnRequestQueue(requestInfo);
}
/// <summary>
/// 添加请求
/// </summary>
/// <param name="funCode"></param>
/// <param name="startAddr"></param>
/// <param name="countOrValue"></param>
/// <param name="equpAddr"></param>
/// <param name="values"></param>
public void AddRequest(byte funCode, int startAddr, int countOrValue, byte equpAddr = 1, int[] values = null)
{
EnRequestQueue(new RequestInfo()
{
FunCode = funCode,
StartAddr = startAddr,
CountOrValue = countOrValue,
EquipAddr = equpAddr,
Values = values
});
}
/// <summary>
/// 收到数据
/// </summary>
/// <param name="msg"></param>
void ReceiveMessage(string msg, byte[] data)
{
LogUtil.Debug($"Receive Data {StringHelper.ToHexString(data)}");
List<byte[]> recvFun = Register.SplitResponse(data);
foreach (var item in recvFun)
{
LogUtil.Debug($"Process Data {StringHelper.ToHexString(item)}");
RequestInfo requestInfo = GetPeek();
if (requestInfo != null)
{
byte[] readData;
bool rtn = GetResponseResult(requestInfo.FunCode, item, out readData);
if (rtn)
{
RemovePeek(true);
if (readData != null)
{
ReceiveData?.Invoke(IP, Port, requestInfo, readData);
LogUtil.Debug($"{StringHelper.ToHexString(readData)}{requestInfo}");
}
}
else
{
rtn = GetResponseResult(requestInfo.FunCode, item, out readData,true);
if(rtn)
{
if (readData != null)
{
ReceiveData?.Invoke(IP, Port, requestInfo, readData);
LogUtil.Debug($"{StringHelper.ToHexString(readData)}{requestInfo}");
}
}
else
{
if (Register.ParseHeader(item, out byte func, out int len))
{
rtn = GetResponseResult(func, item, out readData, true);
if (rtn)
{
if (readData != null)
{
ReceiveData?.Invoke(IP, Port, new RequestInfo() { FunCode = func }, readData);
LogUtil.Debug($"{StringHelper.ToHexString(readData)}");
}
}
}
else
{
requestInfo.SetRequestState(false);
LogUtil.Error($"Request Fail {requestInfo}");
requestInfo.TryTimes++;
//if (requestInfo.TryTimes > TryTimes)//重试一定次数失败删除
//{
// RemovePeek(false);
//}
}
}
}
}
else//设备主动上传收到的信息
{
LogUtil.Debug($"Upload {StringHelper.ToHexString(item)}");
if (Register.ParseHeader(item, out byte func, out int len))
{
bool rtn = GetResponseResult(func, item, out byte[] readData,true);
if (rtn)
{
if (readData != null)
{
ReceiveData?.Invoke(IP, Port, new RequestInfo() { FunCode = func }, readData);
LogUtil.Debug($"{StringHelper.ToHexString(readData)}");
}
}
else
{
LogUtil.Error($"Upload GetResponseResult Fail {StringHelper.ToHexString(item)}");
}
}
else
{
LogUtil.Error($"Upload ParseHeader Fail {StringHelper.ToHexString(item)}");
}
}
}
}
RegisterFunction GetFunction(byte funCode)
{
Register register = GetRegister(funCode);
if (register == null)
{
LogUtil.Error($"不存在的功能码:{StringHelper.ToHexString(funCode)}");
return RegisterFunction.Read;
}
return GetFuncByByte(register, funCode);
}
/// <summary>
/// 获取请求字节数组
/// </summary>
/// <param name="funCode"></param>
/// <param name="startAddr"></param>
/// <param name="countOrValue"></param>
/// <param name="values"></param>
/// <returns></returns>
byte[] GetRequestBytes(byte funCode, int startAddr, int countOrValue, byte equipAddr, int[] values = null)
{
Register register = GetRegister(funCode);
if (register == null)
{
LogUtil.Error($"不存在的功能码:{StringHelper.ToHexString(funCode)}");
return new byte[] { 0x00 };
}
RegisterFunction registerFunction = GetFuncByByte(register, funCode);
if (values != null)
{
ushort[] tmpvalues = new ushort[values.Length];
for (int i = 0; i < values.Length; i++)
{
tmpvalues[i] = (ushort)values[i];
}
return register.GetRequestBytes(registerFunction, (ushort)startAddr, (ushort)countOrValue, equipAddr, tmpvalues);
}
return register.GetRequestBytes(registerFunction, (ushort)startAddr, (ushort)countOrValue, equipAddr, null);
}
/// <summary>
/// 获取响应结果
/// </summary>
/// <param name="funCode">功能码</param>
/// <param name="response">响应的字节数组</param>
/// <param name="data">只有读操作可以使用:读取到的数据</param>
/// <returns>true:操作成功</returns>
bool GetResponseResult(byte funCode, byte[] response, out byte[] data, bool ignoreSerial = false)
{
data = null;
Register register = GetRegister(funCode);
if (register == null)
{
LogUtil.Error($"不存在的功能码:{StringHelper.ToHexString(funCode)}");
return false;
}
RegisterFunction registerFunction = GetFuncByByte(register, funCode);
if (ignoreSerial)
return register.GetReadReault(response, out data);
else
return register.GetResult(registerFunction, response, out data);
}
RegisterFunction GetFuncByByte(Register register, byte funCode)
{
RegisterFunction registerFunction = RegisterFunction.Read;
foreach (RegisterFunction item in register.FunctionCodes.Keys)
{
if (register.FunctionCodes[item].Equals(funCode))
{
registerFunction = item;
break;
}
}
return registerFunction;
}
/// <summary>
/// 根据功能码定位置指定寄存器
/// </summary>
/// <param name="funCode"></param>
/// <returns></returns>
Register GetRegister(byte funCode)
{
return registers.Find(s => s.FunctionCodes.ContainsValue(funCode));
}
/// <summary>
/// 加入队列
/// </summary>
/// <param name="request"></param>
void EnRequestQueue(RequestInfo request)
{
requestInfos.Enqueue(request);
if (!GetFunction(request.FunCode).Equals(RegisterFunction.Read))
LogUtil.Info($"Enqueue Request {request}");
else
LogUtil.Debug($"Enqueue Request {request}");
}
/// <summary>
/// 获取队列第一个请求
/// </summary>
/// <returns></returns>
RequestInfo GetPeek()
{
requestInfos.TryPeek(out RequestInfo request);
return request;
}
/// <summary>
/// 移除队列第一个请求
/// </summary>
/// <returns></returns>
bool RemovePeek(bool success)
{
bool rtn = requestInfos.TryDequeue(out RequestInfo request);
if (success)
{
request.Result = true;
request.FinishTime = DateTime.Now;
if (!GetFunction(request.FunCode).Equals(RegisterFunction.Read))
LogUtil.Info($"Request Success {request}");
else
LogUtil.Debug($"Request Success {request}");
}
else
{
LogUtil.Error($"Try Request {TryTimes} Times Fail {request}");
}
return rtn;
}
void SendRequest()
{
RequestInfo requestInfo = GetPeek();
if (requestInfo != null && (!requestInfo.Requested || requestInfo.RequestTimeOut))
{
bool rtn = tcpClient.Send(GetRequestBytes(requestInfo.FunCode, requestInfo.StartAddr, requestInfo.CountOrValue, requestInfo.EquipAddr, requestInfo.Values));
requestInfo.SetRequestState(rtn);
if (!GetFunction(requestInfo.FunCode).Equals(RegisterFunction.Read))
LogUtil.Info($"Request {requestInfo}");
else
LogUtil.Debug($"Request {requestInfo}");
}
}
}
/// <summary>
/// Modbus请求信息
/// </summary>
public class RequestInfo
{
/// <summary>
/// 功能码
/// </summary>
public byte FunCode { get; set; }
/// <summary>
/// 开始地址
/// </summary>
public int StartAddr { get; set; }
/// <summary>
/// 数量/值
/// </summary>
public int CountOrValue { get; set; }
/// <summary>
/// 设备地址
/// </summary>
public byte EquipAddr { get; set; }
/// <summary>
/// 数组值,写多个值用到
/// </summary>
public int[] Values { get; set; }
/// <summary>
/// 等待一定秒数反转信号。大于0,反转
/// </summary>
public int Seconds { get; set; } = 0;
/// <summary>
/// 是否请求过
/// </summary>
public bool Requested { get; set; } = false;
public int TryTimes { get; set; } = 0;
/// <summary>
/// 请求时间
/// </summary>
public DateTime RequestTime { get; set; } = DateTime.Now;
public DateTime FinishTime { get; set; }
/// <summary>
/// 请求超时
/// </summary>
public bool RequestTimeOut { get { return (DateTime.Now - RequestTime).TotalSeconds > 5; } }
/// <summary>
/// 结果
/// </summary>
public bool Result { get; set; } = false;
/// <summary>
/// 请求
/// </summary>
public void SetRequestState(bool request)
{
Requested = request;
if (request)
RequestTime = DateTime.Now;
}
public override string ToString()
{
return JsonHelper.SerializeObject(this);
}
}
}
using DL.Utils;
using log4net;
using System;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading;
namespace DL.Com.TCP
{
public class TcpClient
{
public delegate void HandleMessage(string message, byte[] data);
private Socket m_clientSocket = null;
private byte[] m_receiveBuffer = new byte[1024];
private HandleMessage onReceived;
public int TimeOutTime = 0;
public string IP { get; set; }
public int Port { get; set; }
public TcpClient()
{
}
/// <summary>
/// 当前连接状态
/// </summary>
public bool IsConnected()
{
if (m_clientSocket == null)
{
return false;
}
return m_clientSocket.Connected;
//if (m_clientSocket.Connected)
//{
// return true;
//}
#region remarks
/********************************************************************************************
* 当Socket.Conneted为false时, 如果您需要确定连接的当前状态,请进行非阻塞、零字节的 Send 调用。
* 如果该调用成功返回或引发 WAEWOULDBLOCK 错误代码 (10035),则该套接字仍然处于连接状态;
* 否则,该套接字不再处于连接状态。
* Depending on http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.connected.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2
********************************************************************************************/
#endregion
try
{
#region 过程
// This is how you can determine whether a socket is still connected.
bool connectState = true;
bool blockingState = m_clientSocket.Blocking;
try
{
byte[] tmp = new byte[1];
m_clientSocket.Blocking = false;
m_clientSocket.Send(tmp, 0, 0);
//Console.WriteLine("Connected!");
connectState = true; //若Send错误会跳去执行catch体,而不会执行其try体里其之后的代码
}
catch (SocketException e)
{
// 10035 == WSAEWOULDBLOCK
if (e.NativeErrorCode.Equals(10035))
{
connectState = true;
}
else
{
connectState = false;
}
}
finally
{
if (m_clientSocket != null && m_clientSocket.Connected)
{
m_clientSocket.Blocking = blockingState;
}
}
//Console.WriteLine("Connected: {0}", client.Connected);
return connectState;
#endregion
}
catch (Exception ex)
{
//Log.Error("IsConnected 出错", log, ex);
return false;
}
}
/// <summary>
/// 连接服务器
/// </summary>
public bool Connect(string serverIP, int serverPort, HandleMessage HandleMessage)
{
IP=serverIP;
Port=serverPort;
m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
if (TimeOutTime <= 0)
{
IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse(serverIP), serverPort);
m_clientSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
try
{
if (!m_clientSocket.Connected)
{
m_clientSocket.Connect(remoteEndPoint);
}
if (m_clientSocket.Connected)
{
m_clientSocket.BeginReceive(m_receiveBuffer, 0, m_receiveBuffer.Length, 0, new AsyncCallback(ReceiveCallBack), null);
onReceived = HandleMessage;
LogUtil.Info("Connect to " + serverIP + ":" + serverPort + " success!");
return true;
}
else
{
LogUtil.Info("Connect to " + serverIP + ":" + serverPort + " fail!");
}
}
catch (Exception ex)
{
LogUtil.Error("Connect to " + serverIP + ":" + serverPort + " fail!", ex);
//m_clientSocket = null;
}
}
else
{
m_clientSocket.ReceiveTimeout = TimeOutTime;
m_clientSocket.SendTimeout = TimeOutTime;
IAsyncResult connResult = m_clientSocket.BeginConnect(serverIP, serverPort, null, null);
connResult.AsyncWaitHandle.WaitOne(this.TimeOutTime, true); //等待2秒
if (!connResult.IsCompleted || (!m_clientSocket.Connected))
{
LogUtil.Info("Connect to " + serverIP + ":" + serverPort + " fail!");
m_clientSocket.Close();
//处理连接不成功的动作
return false;
}
else
{
//处理连接成功的动作
m_clientSocket.BeginReceive(m_receiveBuffer, 0, m_receiveBuffer.Length, 0, new AsyncCallback(ReceiveCallBack), null);
onReceived = HandleMessage;
LogUtil.Info("Connect to " + serverIP + ":" + serverPort + " success!");
return true;
}
}
return false;
}
/// <summary>
/// 断开连接
/// </summary>
public void Close()
{
try
{
if (m_clientSocket != null && m_clientSocket.Connected)
{
m_clientSocket.Shutdown(SocketShutdown.Both);
//Thread.Sleep(300);
//m_clientSocket.Disconnect(true);
//Thread.Sleep(300);
m_clientSocket.Close();
//m_clientSocket = null;
LogUtil.Info("Socket closed!");
}
else
{
LogUtil.Error("No socket is running!");
}
}
catch (Exception ex)
{
LogUtil.Error("close error", ex);
}
}
/// <summary>
/// 发送信息
/// </summary>
public void Send(string strSendData)
{
byte[] sendBuffer = new byte[1024];
sendBuffer = Encoding.UTF8.GetBytes(strSendData);
if (m_clientSocket != null && m_clientSocket.Connected)
{
m_clientSocket.Send(sendBuffer);
LogUtil.Debug("Send >> " + strSendData);
}
}
public bool Send(byte[] bytes)
{
if (m_clientSocket != null && m_clientSocket.Connected)
{
m_clientSocket.Send(bytes);
LogUtil.Debug("Send >> " + StringHelper.ToHexString(bytes));
return true;
}
return false;
}
private void ReceiveCallBack(IAsyncResult ar)
{
try
{
if (m_clientSocket != null && m_clientSocket.Connected)
{
int REnd = m_clientSocket.EndReceive(ar);
string strReceiveData = Encoding.Default.GetString(m_receiveBuffer, 0, REnd);
byte[] tmp = new byte[REnd];
Array.Copy(m_receiveBuffer, tmp, REnd);
onReceived(strReceiveData, tmp);
Thread.Sleep(100);
m_clientSocket.BeginReceive(m_receiveBuffer, 0, m_receiveBuffer.Length, 0, new AsyncCallback(ReceiveCallBack), null);
}
}
catch (Exception ex)
{
LogUtil.Error("socket received error", ex);
}
}
}
}
using DL.Utils;
using log4net;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace DL.Com.TCP
{
public class TcpServer
{
/// <summary>
/// 接受消息时的间隔
/// </summary>
public static int ReviceMsgMS = 10;
private Thread m_serverThread;
private Socket m_serverSocket;
public delegate void ReviceMsgEventHandler(TcpClientBean client, string Msg,byte[] data);
public delegate void ClientOffLineEventHandler(TcpClientBean client);
public delegate void AcceptClientEventHandler(TcpClientBean client);
public event ReviceMsgEventHandler ReviceMsgEvent;
public event AcceptClientEventHandler AcceptClientEvent;
public event ClientOffLineEventHandler ClientOfflineEvent;
private bool isRun = false;
private int serverPort = 0;
public TcpServer(int m_serverPort)
{
this.serverPort = m_serverPort;
}
private void logLocalIp()
{
string[] addresses = GetLocalAddresses();
string iplist = "本机IP:[";
if (addresses.Length > 0)
{
for (int i = 0; i < addresses.Length; i++)
{
if (addresses.Length != 0)
{
iplist = iplist + " " + addresses[i];
}
}
}
LogUtil.Info(iplist + "]");
}
public bool Connected { get { return m_serverSocket != null && m_serverSocket.Connected; } }
/// <summary>
/// 开始服务
/// </summary>
public bool Start()
{
try
{
isRun = true;
m_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, serverPort);
m_serverSocket.Bind(localEndPoint);
m_serverSocket.Listen(10);
m_serverThread = new Thread(new ThreadStart(ReceiveAccept));
m_serverThread.Start();
LogUtil.Info(" Server start listen : " + serverPort);
logLocalIp();
return true;
//this.AddRunningInfo(">> " + DateTime.Now.ToString() + " Server started.");
}
catch (SocketException se)
{
LogUtil.Error("Tcpserver Start 报错",se);
}
catch (Exception ex)
{
LogUtil.Error("Tcpserver Start 报错", ex);
}
return false;
}
/// <summary>
/// 停止服务
/// </summary>
public bool Stop()
{
try
{
isRun = false;
m_serverThread.Interrupt(); // 线程终止
m_serverSocket.Close(); // Socket Close
return true;
}
catch (Exception ex)
{
LogUtil.Error("Tcpserver Stop报错", ex);
}
return false;
}
private void ReceiveAccept()
{
while (isRun)
{
TcpClientBean client = new TcpClientBean();
try
{
client.ClientSocket = m_serverSocket.Accept();
IPEndPoint clientipe = (IPEndPoint)client.ClientSocket.RemoteEndPoint;
client.IP = clientipe.Address.ToString();
client.Port = clientipe.Port;
LogUtil.Info("[" + serverPort + "]有新的客户端连接上:[" + client.AddStr + "]");
AcceptClientEvent?.Invoke(client);
Task.Factory.StartNew(delegate { ReceiveMessages(client); });
}
catch (Exception ex)
{
LogUtil.Error("ReceiveAccept方法,客户端【" + client.AddStr + "】", ex);
//throw new Exception(ex.Message);
}
}
}
// private StringBuilder sb = new StringBuilder(); //这个是用来保存:接收到了的,但是还没有结束的消息
private int receiveBufferSize = 1024;
public string terminateString = "\r\n";
public void ReceiveMessages(TcpClientBean client) //这个函数会被以线程方式运行
{
try
{
StringBuilder sb = new StringBuilder();
Socket socket = (Socket)client.ClientSocket;
while (true)
{
byte[] buffer = new byte[receiveBufferSize]; //buffer大小,此处为1024
if(socket.Poll(0,SelectMode.SelectRead))
{
int receivedSize = socket.Receive(buffer);
if (receivedSize > 0)
{
string rawMsg = Encoding.ASCII.GetString(buffer, 0, receivedSize);
byte[] data = new byte[receivedSize];
Array.Copy(buffer, 0, data, 0, receivedSize);
int rnFixLength = terminateString.Length; //这个是指消息结束符的长度,此处为\r\n
if (rnFixLength == 0)//无结束符
{
this.ReviceMsgEvent?.Invoke(client, rawMsg, data);//无消息结束符,直接触发消息接收完成事件
}
else
{
for (int i = 0; i < rawMsg.Length;) //遍历接收到的整个buffer文本
{
if (i <= rawMsg.Length - rnFixLength)
{
if (rawMsg.Substring(i, rnFixLength) != terminateString)//非消息结束符,则加入sb
{
sb.Append(rawMsg[i]);
i++;
}
else
{
this.ReviceMsgEvent?.Invoke(client, sb.ToString(), data);//找到了消息结束符,触发消息接收完成事件
sb = new StringBuilder();
i += rnFixLength;
}
}
else
{
sb.Append(rawMsg[i]);
i++;
}
}
}
}
else
{
ClientOfflineEvent?.Invoke(client);
LogUtil.Info($"客户端【{client.AddStr}】已断开");
break;
}
}
Thread.Sleep(ReviceMsgMS);
}
}
catch (SocketException e)
{
LogUtil.Error($"客户端【{client.AddStr}】:{e.StackTrace}", e);
ClientOfflineEvent?.Invoke(client);
}
catch (Exception ex)
{
LogUtil.Error($"客户端【{client.AddStr}】:{ex.StackTrace}", ex);
ClientOfflineEvent?.Invoke(client);
}
}
//private void ReceiveMessages(Client client)
//{
// try
// {
// while (true)
// {
// byte[] receiveBuffer = new byte[1024];
// //int size = ;
// int size = client.ClientSocket.Receive(receiveBuffer);
// string strReceiveData = Encoding.ASCII.GetString(receiveBuffer, 0, size);
// if (!string.IsNullOrEmpty(strReceiveData))
// {
// Log.info(LOGGER, "收到数据:" + strReceiveData);
// // this.AddRunningInfo(">> Receive data from [" + client.ClientSocket.RemoteEndPoint.ToString()+ "]:" + strReceiveData);
// string strSendData = "OK. The content is:" + strReceiveData;
// //Log.info(LOGGER, "OK. The content is:" + strReceiveData);
// int sendBufferSize = Encoding.Unicode.GetByteCount(strSendData);
// byte[] sendBuffer = new byte[sendBufferSize];
// sendBuffer = Encoding.Unicode.GetBytes(strSendData);
// client.ClientSocket.Send(sendBuffer);
// }
// }
// }
// catch (SocketException e)
// {
// Log.error(LOGGER, e.ToString());
// }
// catch (Exception ex)
// {
// LOGGER.Error(ex.ToString());
// }
//}
/// <summary>
/// 获取本机地址列表
/// </summary>
public static string[] GetLocalAddresses()
{
// 获取主机名
string strHostName = Dns.GetHostName();
// 根据主机名进行查找
IPHostEntry iphostentry = Dns.GetHostEntry(strHostName);
List<string> retval = new List<string>();
foreach (IPAddress ipaddress in iphostentry.AddressList)
{
if (ipaddress.AddressFamily != AddressFamily.InterNetworkV6)
{
retval.Add(ipaddress.ToString());
}
}
return retval.ToArray();
}
/// <summary>
/// 端口是否被占用
/// </summary>
/// <param name="port"></param>
/// <returns></returns>
public static bool PortInUse(int port)
{
bool result = false;
IPGlobalProperties iPGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint[] activeTcpListeners = iPGlobalProperties.GetActiveTcpListeners();
IPEndPoint[] array = activeTcpListeners;
for (int i = 0; i < array.Length; i++)
{
IPEndPoint iPEndPoint = array[i];
bool flag = iPEndPoint.Port == port;
if (flag)
{
string[] expr_36 = new string[5];
expr_36[0] = "IP【";
int arg_53_1 = 1;
IPAddress expr_47 = iPEndPoint.Address;
expr_36[arg_53_1] = ((expr_47 != null) ? expr_47.ToString() : null);
expr_36[2] = "】port【";
expr_36[3] = iPEndPoint.Port.ToString();
expr_36[4] = "】已使用";
LogUtil.Error(string.Concat(expr_36));
result = true;
break;
}
}
return result;
}
public bool IsOnline(string addr = "")
{
return isRun;
}
public string GetAddr()
{
return $"{string.Join(",", GetLocalAddresses())}:{serverPort}";
}
}
/// <summary>
/// 客户端会话信息类
/// </summary>
public class TcpClientBean
{
Socket m_clientSocket;
public string IP = "";
public string AddStr { get { return $"{IP}:{Port}"; } }
public int Port = 0;
public TcpClientBean() { }
public void Close()
{
if (m_clientSocket != null && m_clientSocket.Connected)
{
m_clientSocket.Shutdown(SocketShutdown.Both);
m_clientSocket.Close();
}
}
public Socket ClientSocket
{
get { return m_clientSocket; }
set { this.m_clientSocket = value; }
}
}
}

using DL.Utils;
using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace DL.Com
{
public class UdpServer
{
static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod()?.DeclaringType);
private Thread m_serverThread;
private Socket udpServer;
public delegate void ReviceMsg(EndPoint address, string Msg);
/// <summary>
/// 接受到数据事件
/// </summary>
public event ReviceMsg ReviceMsgEvent;
private bool isRun = true;
private int serverPort;
private void logLocalIp()
{
string[] addresses = GetLocalAddresses();
string iplist = "本机IP:[";
if (addresses.Length > 0)
{
for (int i = 0; i < addresses.Length; i++)
{
if (addresses.Length != 0)
{
iplist = iplist + " " + addresses[i];
}
}
}
LogUtil.Info(iplist + "]",log);
}
public UdpServer(int m_serverPort)
{
serverPort = m_serverPort;
}
/// <summary>
/// 开始服务
/// </summary>
public bool Start()
{
try
{
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, serverPort);//定义一网络端点
udpServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);//定义一个Socket
udpServer.Bind(ipep);//Socket与本地的一个终结点相关联
m_serverThread = new Thread(new ThreadStart(ReceiveData));
m_serverThread.Start();
logLocalIp();
isRun = true;
return true;
}
catch (Exception ex)
{
LogUtil.Error("启动udpserver出错" ,log,ex);
}
return false;
}
/// <summary>
/// 停止服务
/// </summary>
public bool Stop()
{
try
{
isRun = false;
m_serverThread.Interrupt(); // 线程终止
udpServer.Close(); // Socket Close
return true;
}
catch (Exception ex)
{
LogUtil.Error("Stop Udpserver出错",log,ex);
}
return false;
}
private StringBuilder sb = new StringBuilder(); //这个是用来保存:接收到了的,但是还没有结束的消息
private int receiveBufferSize = 1024;
/// <summary>
/// 结束符
/// </summary>
public string terminateString = "\r";
private void ReceiveData()
{
try
{
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);//定义要发送的计算机的地址
EndPoint Remote = (EndPoint)(sender);//
while (true)
{
byte[] buffer = new byte[receiveBufferSize];
int receivedSize = udpServer.ReceiveFrom(buffer, ref Remote);
if (receivedSize > 0)
{
string rawMsg = Encoding.ASCII.GetString(buffer, 0, receivedSize);
int rnFixLength = terminateString.Length; //这个是指消息结束符的长度,此处为\r\n
for (int i = 0; i < rawMsg.Length;) //遍历接收到的整个buffer文本
{
if (i <= rawMsg.Length - rnFixLength)
{
if (rawMsg.Substring(i, rnFixLength) != terminateString)//非消息结束符,则加入sb
{
sb.Append(rawMsg[i]);
i++;
}
else
{
this.ReviceMsgEvent.Invoke(Remote, sb.ToString());//找到了消息结束符,触发消息接收完成事件
sb = new StringBuilder();
i += rnFixLength;
}
}
else
{
sb.Append(rawMsg[i]);
i++;
}
}
}
Thread.Sleep(500);
}
}
catch (Exception ex)
{
LogUtil.Error("启动udpserver出错:" ,log,ex);
}
}
/// <summary>
/// 获取本机地址列表
/// </summary>
public string[] GetLocalAddresses()
{
// 获取主机名
string strHostName = Dns.GetHostName();
// 根据主机名进行查找
IPHostEntry iphostentry = Dns.GetHostEntry(strHostName);
string[] retval = new string[iphostentry.AddressList.Length];
int i = 0;
foreach (IPAddress ipaddress in iphostentry.AddressList)
{
if (ipaddress.AddressFamily != AddressFamily.InterNetworkV6)
{
retval[i] = ipaddress.ToString();
i++;
}
}
return retval;
}
public bool IsOnline(string addr = "")
{
return isRun;
}
public string GetAddr()
{
return $"{string.Join(",",GetLocalAddresses())}:{serverPort}";
}
}
}
...@@ -56,6 +56,9 @@ ...@@ -56,6 +56,9 @@
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\..\dll\Client.dll</HintPath> <HintPath>..\..\dll\Client.dll</HintPath>
</Reference> </Reference>
<Reference Include="DL.DeviceLib">
<HintPath>..\..\..\..\..\..\SharedRefDll\Neotel\DL.DeviceLib\Debug\netstandard2.0\DL.DeviceLib.dll</HintPath>
</Reference>
<Reference Include="HFReader9CSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64"> <Reference Include="HFReader9CSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\..\dll\RFID\HFReader9CSharp.dll</HintPath> <HintPath>..\..\dll\RFID\HFReader9CSharp.dll</HintPath>
...@@ -94,6 +97,7 @@ ...@@ -94,6 +97,7 @@
<Compile Include="doubleLine\DoubleLineBean_lineShelf.cs" /> <Compile Include="doubleLine\DoubleLineBean_lineShelf.cs" />
<Compile Include="doubleLine\DoubleLineBean_S1Shelf.cs" /> <Compile Include="doubleLine\DoubleLineBean_S1Shelf.cs" />
<Compile Include="doubleLine\RobotMoveBean.cs" /> <Compile Include="doubleLine\RobotMoveBean.cs" />
<Compile Include="Line\AllLine.cs" />
<Compile Include="manager\LineManager.cs" /> <Compile Include="manager\LineManager.cs" />
<Compile Include="bean\WaitUtil.cs" /> <Compile Include="bean\WaitUtil.cs" />
<Compile Include="agvClient\AgvClient.cs" /> <Compile Include="agvClient\AgvClient.cs" />
......
using DL.DeviceLib;
using log4net.Util;
using OnlineStore.Common;
using OnlineStore.LoadCSVLibrary;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Management;
namespace OnlineStore.DeviceLibrary
{
internal class AllLine
{
/// <summary>
/// 左下层链条
/// </summary>
public static LineMonitor LeftLowLine;
public static void InitLine()
{
LineMonitor.Log.LogEvent += Log_LogEvent;
LeftLowLine = new LineMonitor("左下层链条");
LeftLowLine.LineOperateEvent += LeftLowLine_LineOperateEvent;
LeftLowLine.LineStateEvent += LeftLowLine_LineStateEvent;
}
private static void Log_LogEvent(LogEventArgs args)
{
switch (args.LogLevel)
{
case LogLevel.Error:
LogUtil.error(args.ToLogFile());
break;
case LogLevel.Debug:
LogUtil.debug(args.ToLogFile());
break;
case LogLevel.Info:
LogUtil.info(args.ToLogFile());
break;
case LogLevel.Warn:
LogUtil.error(args.ToLogFile());
break;
case LogLevel.Fatal:
LogUtil.error(args.ToLogFile());
break;
}
}
private static bool LeftLowLine_LineStateEvent(LineRunParam runParam)
{
switch (runParam)
{
case LineRunParam.Run:
return IOManager.IOValue(IO_Type.LLown_LineRun).Equals(IO_VALUE.HIGH);
case LineRunParam.Stop:
return IOManager.IOValue(IO_Type.LLown_LineRun).Equals(IO_VALUE.LOW);
case LineRunParam.BackRun:
return false;
default: return false;
}
}
private static void LeftLowLine_LineOperateEvent(LineRunParam runParam)
{
switch (runParam)
{
case LineRunParam.Run:
IOManager.IOMove(IO_Type.LLown_LineRun, IO_VALUE.HIGH);
break;
case LineRunParam.Stop:
IOManager.IOMove(IO_Type.LLown_LineRun, IO_VALUE.LOW);
break;
case LineRunParam.BackRun:
break;
}
}
}
}
...@@ -198,8 +198,8 @@ namespace OnlineStore.DeviceLibrary ...@@ -198,8 +198,8 @@ namespace OnlineStore.DeviceLibrary
if (!wait.IsEnd) if (!wait.IsEnd)
{ {
if (wait.IoType.Equals(IO_Type.LHigh_LineRun) || wait.IoType.Equals(IO_Type.LLown_LineRun) if (wait.IoType.Equals(IO_Type.LHigh_LineRun)
|| wait.IoType.Equals(IO_Type.S1_LineRun) || wait.IoType.Equals(IO_Type.S1_LineBackRun)) || wait.IoType.Equals(IO_Type.S1_LineRun) || wait.IoType.Equals(IO_Type.S1_LineBackRun))//|| wait.IoType.Equals(IO_Type.LLown_LineRun)
{ {
IOMove(wait.IoType, wait.IoValue); IOMove(wait.IoType, wait.IoValue);
LogInfo(" [" + moveInfo.MoveType + "][" + moveInfo.MoveStep + "]重写DO: " + wait.ToStr()); LogInfo(" [" + moveInfo.MoveType + "][" + moveInfo.MoveStep + "]重写DO: " + wait.ToStr());
......
...@@ -62,6 +62,7 @@ namespace OnlineStore.DeviceLibrary ...@@ -62,6 +62,7 @@ namespace OnlineStore.DeviceLibrary
{ {
ShelfWaitTime = 2000; ShelfWaitTime = 2000;
} }
AllLine.InitLine();
} }
......
...@@ -277,12 +277,13 @@ namespace OnlineStore.DeviceLibrary ...@@ -277,12 +277,13 @@ namespace OnlineStore.DeviceLibrary
IOMove(IO_Type.M_RightStopCylinder, IO_VALUE.HIGH); IOMove(IO_Type.M_RightStopCylinder, IO_VALUE.HIGH);
IOMove(IO_Type.LLown_LineRun, IO_VALUE.HIGH); //IOMove(IO_Type.LLown_LineRun, IO_VALUE.HIGH);
AllLine.LeftLowLine.LineRun(Name, false, 0, "放大料架到左侧");
IOMove(IO_Type.M_LineRun, IO_VALUE.HIGH); IOMove(IO_Type.M_LineRun, IO_VALUE.HIGH);
SOneMoveInfo.WaitList.Add(WaitResultInfo.WaitIO(IO_Type.M_LeftStopCylinder, IO_VALUE.HIGH, true)); SOneMoveInfo.WaitList.Add(WaitResultInfo.WaitIO(IO_Type.M_LeftStopCylinder, IO_VALUE.HIGH, true));
SOneMoveInfo.WaitList.Add(WaitResultInfo.WaitIO(IO_Type.M_RightStopCylinder, IO_VALUE.HIGH, true)); SOneMoveInfo.WaitList.Add(WaitResultInfo.WaitIO(IO_Type.M_RightStopCylinder, IO_VALUE.HIGH, true));
SOneMoveInfo.WaitList.Add(WaitResultInfo.WaitIO(IO_Type.LLown_LineRun, IO_VALUE.HIGH, true)); //SOneMoveInfo.WaitList.Add(WaitResultInfo.WaitIO(IO_Type.LLown_LineRun, IO_VALUE.HIGH, true));
SOneMoveInfo.WaitList.Add(WaitResultInfo.WaitIO(IO_Type.M_LineRun, IO_VALUE.HIGH, true)); SOneMoveInfo.WaitList.Add(WaitResultInfo.WaitIO(IO_Type.M_LineRun, IO_VALUE.HIGH, true));
// SOneMoveInfo.WaitList.Add(WaitResultInfo.WaitIO(IO_Type.LLow_StopCheck3, IO_VALUE.LOW)); // SOneMoveInfo.WaitList.Add(WaitResultInfo.WaitIO(IO_Type.LLow_StopCheck3, IO_VALUE.LOW));
...@@ -354,7 +355,8 @@ namespace OnlineStore.DeviceLibrary ...@@ -354,7 +355,8 @@ namespace OnlineStore.DeviceLibrary
SOneMoveInfo.TimeOutSeconds = 15; SOneMoveInfo.TimeOutSeconds = 15;
S1_StopMove(SOneMoveInfo, IO_VALUE.HIGH); S1_StopMove(SOneMoveInfo, IO_VALUE.HIGH);
IOMove(IO_Type.S1_PosStopCylinder, IO_VALUE.LOW); IOMove(IO_Type.S1_PosStopCylinder, IO_VALUE.LOW);
IOMove(IO_Type.LLown_LineRun, IO_VALUE.LOW); //IOMove(IO_Type.LLown_LineRun, IO_VALUE.LOW);
AllLine.LeftLowLine.LineStop(Name, "送料架到S1线体", true);
IOMove(IO_Type.LLow_StopCylinder2, IO_VALUE.LOW); IOMove(IO_Type.LLow_StopCylinder2, IO_VALUE.LOW);
// IOMove(IO_Type.S1_LineRun, IO_VALUE.HIGH); // IOMove(IO_Type.S1_LineRun, IO_VALUE.HIGH);
IOMove(IO_Type.M_LineRun, IO_VALUE.HIGH); IOMove(IO_Type.M_LineRun, IO_VALUE.HIGH);
......
...@@ -106,8 +106,8 @@ namespace OnlineStore.DeviceLibrary ...@@ -106,8 +106,8 @@ namespace OnlineStore.DeviceLibrary
{ {
LowProcess = true; LowProcess = true;
LogUtil.info("左侧双层线_左下层放料架到阻挡2"); LogUtil.info("左侧双层线_左下层放料架到阻挡2");
IOMove(IO_Type.LLown_LineRun, IO_VALUE.HIGH, 30000); //IOMove(IO_Type.LLown_LineRun, IO_VALUE.HIGH, 30000);
AllLine.LeftLowLine.LineRun(Name, false, 30, "放料架到阻挡2");
IOMove(IO_Type.LLow_StopCylinder1, IO_VALUE.HIGH, 2000); IOMove(IO_Type.LLow_StopCylinder1, IO_VALUE.HIGH, 2000);
if (WaitIo(IO_Type.LLow_StopCheck2, IO_VALUE.HIGH, 20000, "左侧_下层放料架到阻挡2")) if (WaitIo(IO_Type.LLow_StopCheck2, IO_VALUE.HIGH, 20000, "左侧_下层放料架到阻挡2"))
{ {
...@@ -122,7 +122,10 @@ namespace OnlineStore.DeviceLibrary ...@@ -122,7 +122,10 @@ namespace OnlineStore.DeviceLibrary
{ {
if (LowProcess) if (LowProcess)
{ {
KeepLineRun(IO_Type.LLown_LineRun); if (!AllLine.LeftLowLine.IsLineRun)
{
AllLine.LeftLowLine.LineRun(Name, false, 5, "放料架到阻挡2,链条已停止,重新运行");
}
} }
lowWatch.Stop(); lowWatch.Stop();
} }
...@@ -183,7 +186,7 @@ namespace OnlineStore.DeviceLibrary ...@@ -183,7 +186,7 @@ namespace OnlineStore.DeviceLibrary
else else
{ {
inLineWatch.Stop(); inLineWatch.Stop();
if (MoveInfo.MoveType.Equals(LineMoveType.LeftShelf)&&MoveInfo.MoveStep.Equals(MoveStep.SI04_InStopDown)) if (MoveInfo.MoveType.Equals(LineMoveType.LeftShelf) && MoveInfo.MoveStep.Equals(MoveStep.SI04_InStopDown))
{ {
} }
else else
...@@ -238,7 +241,8 @@ namespace OnlineStore.DeviceLibrary ...@@ -238,7 +241,8 @@ namespace OnlineStore.DeviceLibrary
} }
else if (LeftUpdownRFID.StartsWith(Static_String.BigShelf_RFID_Prefix)) else if (LeftUpdownRFID.StartsWith(Static_String.BigShelf_RFID_Prefix))
{ {
CheckAndMove(IO_Type.LLown_LineRun, IO_VALUE.HIGH); //CheckAndMove(IO_Type.LLown_LineRun, IO_VALUE.HIGH);
AllLine.LeftLowLine.LineRun(Name, false, 0, $"提升机有料架{LeftUpdownRFID}");
} }
} }
...@@ -474,7 +478,15 @@ namespace OnlineStore.DeviceLibrary ...@@ -474,7 +478,15 @@ namespace OnlineStore.DeviceLibrary
{ {
moveInfo.WaitList.Add(WaitResultInfo.WaitIO(IO_Type.LLown_LineRun, value, true)); moveInfo.WaitList.Add(WaitResultInfo.WaitIO(IO_Type.LLown_LineRun, value, true));
} }
CheckAndMove(IO_Type.LLown_LineRun, value); //CheckAndMove(IO_Type.LLown_LineRun, value);
if(value.Equals(IO_VALUE.HIGH))
{
AllLine.LeftLowLine.LineRun(Name, false, 0, "LeftLineMove");
}
else if(value.Equals(IO_VALUE.LOW))
{
AllLine.LeftLowLine.LineStop(Name, "LeftLineMove", true);
}
} }
} }
......
文件属性发生变化
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!