Add receiver (not complete)
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
|||||||
@@ -169,4 +169,9 @@ namespace Modbus.Net.Modbus
|
|||||||
return newContent.ToArray();
|
return newContent.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ModbusRtuProtocolReceiverBytesExtend : ModbusRtuProtocolLinkerBytesExtend
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
34
Modbus.Net/Modbus.Net.Modbus/ModbusRtuProtocolReceiver.cs
Normal file
34
Modbus.Net/Modbus.Net.Modbus/ModbusRtuProtocolReceiver.cs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Modbus.Net.Modbus
|
||||||
|
{
|
||||||
|
public class ModbusRtuProtocolReceiver : ProtocolReceiver
|
||||||
|
{
|
||||||
|
public ModbusRtuProtocolReceiver(string com, int slaveAddress)
|
||||||
|
: base(com, slaveAddress)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Func<byte[], ReceiveDataDef> DataExplain
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return receiveBytes =>
|
||||||
|
{
|
||||||
|
var writeContent = receiveBytes.Length > 6 ? new byte[receiveBytes.Length - 7] : null;
|
||||||
|
if (receiveBytes.Length > 6) Array.Copy(receiveBytes, 7, writeContent, 0, receiveBytes.Length - 7);
|
||||||
|
return new ReceiveDataDef()
|
||||||
|
{
|
||||||
|
SlaveAddress = receiveBytes[0],
|
||||||
|
FunctionCode = receiveBytes[1],
|
||||||
|
StartAddress = (ushort)(receiveBytes[2] * 256 + receiveBytes[3]),
|
||||||
|
Count = (ushort)(receiveBytes[4] * 256 + receiveBytes[5]),
|
||||||
|
WriteByteCount = (byte)(receiveBytes.Length > 6 ? receiveBytes[6] : 0),
|
||||||
|
WriteContent = writeContent
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -292,12 +292,13 @@ namespace Modbus.Net.Modbus
|
|||||||
var outputStruct = await
|
var outputStruct = await
|
||||||
Wrapper.SendReceiveAsync<WriteDataModbusOutputStruct>(Wrapper[typeof(WriteDataModbusProtocol)],
|
Wrapper.SendReceiveAsync<WriteDataModbusOutputStruct>(Wrapper[typeof(WriteDataModbusProtocol)],
|
||||||
inputStruct);
|
inputStruct);
|
||||||
|
var ans = outputStruct?.WriteCount * 2 == BigEndianLsbValueHelper.Instance.ObjectArrayToByteArray(setContents).Length;
|
||||||
return new ReturnStruct<bool>()
|
return new ReturnStruct<bool>()
|
||||||
{
|
{
|
||||||
Datas = outputStruct?.WriteCount == setContents.Length,
|
Datas = ans,
|
||||||
IsSuccess = outputStruct?.WriteCount == setContents.Length,
|
IsSuccess = ans,
|
||||||
ErrorCode = outputStruct?.WriteCount == setContents.Length ? 0 : -2,
|
ErrorCode = ans ? 0 : -2,
|
||||||
ErrorMsg = outputStruct?.WriteCount == setContents.Length ? "" : "Data length mismatch"
|
ErrorMsg = ans ? "" : "Data length mismatch"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
catch (ModbusProtocolErrorException e)
|
catch (ModbusProtocolErrorException e)
|
||||||
|
|||||||
7
Modbus.Net/Modbus.Net.Modbus/ModbusUtilityServer.cs
Normal file
7
Modbus.Net/Modbus.Net.Modbus/ModbusUtilityServer.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Modbus.Net.Modbus
|
||||||
|
{
|
||||||
|
public class ModbusUtilityServer
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,7 +49,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Modbus.Net.HJ212", "Modbus.
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Modbus.Net.CodeGenerator", "Modbus.Net.CodeGenerator\Modbus.Net.CodeGenerator.csproj", "{D3210531-BA79-49B2-9F99-09FD0E1627B6}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Modbus.Net.CodeGenerator", "Modbus.Net.CodeGenerator\Modbus.Net.CodeGenerator.csproj", "{D3210531-BA79-49B2-9F99-09FD0E1627B6}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MachineJob.CodeGenerator", "..\Samples\MachineJob.CodeGenerator\MachineJob.CodeGenerator.csproj", "{7337BC9A-ED07-463D-8FCD-A82896CEC6BE}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MachineJob.CodeGenerator", "..\Samples\MachineJob.CodeGenerator\MachineJob.CodeGenerator.csproj", "{7337BC9A-ED07-463D-8FCD-A82896CEC6BE}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ModbusTcpToRtu", "..\Samples\ModbusTcpToRtu\ModbusTcpToRtu.csproj", "{9CA7E35C-B5BC-4743-8732-1D8912AA12D8}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleModbusRtuServer", "..\Samples\SampleModbusRtuServer\SampleModbusRtuServer.csproj", "{CB85D4B3-EEA2-431F-A47F-1DE7FB0A4802}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@@ -211,6 +215,22 @@ Global
|
|||||||
{7337BC9A-ED07-463D-8FCD-A82896CEC6BE}.Release|Any CPU.Build.0 = Release|Any CPU
|
{7337BC9A-ED07-463D-8FCD-A82896CEC6BE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{7337BC9A-ED07-463D-8FCD-A82896CEC6BE}.Release|x64.ActiveCfg = Release|Any CPU
|
{7337BC9A-ED07-463D-8FCD-A82896CEC6BE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
{7337BC9A-ED07-463D-8FCD-A82896CEC6BE}.Release|x64.Build.0 = Release|Any CPU
|
{7337BC9A-ED07-463D-8FCD-A82896CEC6BE}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{9CA7E35C-B5BC-4743-8732-1D8912AA12D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{9CA7E35C-B5BC-4743-8732-1D8912AA12D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{9CA7E35C-B5BC-4743-8732-1D8912AA12D8}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{9CA7E35C-B5BC-4743-8732-1D8912AA12D8}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{9CA7E35C-B5BC-4743-8732-1D8912AA12D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{9CA7E35C-B5BC-4743-8732-1D8912AA12D8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{9CA7E35C-B5BC-4743-8732-1D8912AA12D8}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{9CA7E35C-B5BC-4743-8732-1D8912AA12D8}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{CB85D4B3-EEA2-431F-A47F-1DE7FB0A4802}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{CB85D4B3-EEA2-431F-A47F-1DE7FB0A4802}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{CB85D4B3-EEA2-431F-A47F-1DE7FB0A4802}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{CB85D4B3-EEA2-431F-A47F-1DE7FB0A4802}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{CB85D4B3-EEA2-431F-A47F-1DE7FB0A4802}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{CB85D4B3-EEA2-431F-A47F-1DE7FB0A4802}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{CB85D4B3-EEA2-431F-A47F-1DE7FB0A4802}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{CB85D4B3-EEA2-431F-A47F-1DE7FB0A4802}.Release|x64.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -222,6 +242,8 @@ Global
|
|||||||
{AA3A42D2-0502-41D3-929A-BAB729DF07D6} = {3597B5C5-45B9-4ECB-92A3-D0FFBE47920A}
|
{AA3A42D2-0502-41D3-929A-BAB729DF07D6} = {3597B5C5-45B9-4ECB-92A3-D0FFBE47920A}
|
||||||
{414956B8-DBD4-414C-ABD3-565580739646} = {3597B5C5-45B9-4ECB-92A3-D0FFBE47920A}
|
{414956B8-DBD4-414C-ABD3-565580739646} = {3597B5C5-45B9-4ECB-92A3-D0FFBE47920A}
|
||||||
{7337BC9A-ED07-463D-8FCD-A82896CEC6BE} = {3597B5C5-45B9-4ECB-92A3-D0FFBE47920A}
|
{7337BC9A-ED07-463D-8FCD-A82896CEC6BE} = {3597B5C5-45B9-4ECB-92A3-D0FFBE47920A}
|
||||||
|
{9CA7E35C-B5BC-4743-8732-1D8912AA12D8} = {3597B5C5-45B9-4ECB-92A3-D0FFBE47920A}
|
||||||
|
{CB85D4B3-EEA2-431F-A47F-1DE7FB0A4802} = {3597B5C5-45B9-4ECB-92A3-D0FFBE47920A}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {AF00D64E-3C70-474A-8A81-E9E48017C4B5}
|
SolutionGuid = {AF00D64E-3C70-474A-8A81-E9E48017C4B5}
|
||||||
|
|||||||
@@ -41,6 +41,20 @@ namespace Modbus.Net
|
|||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ContentType? GetContent<ContentType>(string path, string key) where ContentType : class
|
||||||
|
{
|
||||||
|
var root = configuration.GetSection("Modbus.Net");
|
||||||
|
var firstColon = path.IndexOf(":");
|
||||||
|
while (firstColon != -1)
|
||||||
|
{
|
||||||
|
root = root?.GetSection(path.Substring(0, firstColon));
|
||||||
|
path = path.Substring(firstColon + 1);
|
||||||
|
firstColon = path.IndexOf(":");
|
||||||
|
}
|
||||||
|
root = root?.GetSection(path);
|
||||||
|
return root?.GetSection(key).Get<ContentType>();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 根据路径,直接查找路径上是否有该元素
|
/// 根据路径,直接查找路径上是否有该元素
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Modbus.Net
|
namespace Modbus.Net
|
||||||
@@ -14,18 +15,10 @@ namespace Modbus.Net
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class BaseConnector<TParamIn, TParamOut> : IConnectorWithController<TParamIn, TParamOut> where TParamIn : class
|
public abstract class BaseConnector<TParamIn, TParamOut> : IConnectorWithController<TParamIn, TParamOut> where TParamIn : class
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// 数据返回代理参数
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public delegate MessageReturnCallbackArgs<TParamIn> MessageReturnDelegate(object sender, MessageReturnArgs<TParamOut> args);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 数据返回代理
|
/// 数据返回代理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event MessageReturnDelegate MessageReturn;
|
public Func<MessageReturnArgs<TParamOut>, MessageReturnCallbackArgs<TParamIn>> MessageReturn { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void AddController(IController controller)
|
public void AddController(IController controller)
|
||||||
@@ -76,7 +69,7 @@ namespace Modbus.Net
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected TParamIn InvokeReturnMessage(TParamOut receiveMessage)
|
protected TParamIn InvokeReturnMessage(TParamOut receiveMessage)
|
||||||
{
|
{
|
||||||
return MessageReturn?.Invoke(this, new MessageReturnArgs<TParamOut> { ReturnMessage = receiveMessage })?.SendMessage;
|
return MessageReturn?.Invoke(new MessageReturnArgs<TParamOut> { ReturnMessage = receiveMessage })?.SendMessage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -500,7 +500,7 @@ namespace Modbus.Net
|
|||||||
if (_receiveThread == null)
|
if (_receiveThread == null)
|
||||||
{
|
{
|
||||||
_receiveThreadCancel = new CancellationTokenSource();
|
_receiveThreadCancel = new CancellationTokenSource();
|
||||||
_receiveThread = Task.Run(async ()=>await ReceiveMessage(_receiveThreadCancel.Token), _receiveThreadCancel.Token);
|
_receiveThread = Task.Run(async () => await ReceiveMessage(_receiveThreadCancel.Token), _receiveThreadCancel.Token);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _receiveThread;
|
await _receiveThread;
|
||||||
|
|||||||
@@ -32,18 +32,10 @@ namespace Modbus.Net
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class EventHandlerConnector<TParamIn, TParamOut> : ChannelHandlerAdapter, IConnectorWithController<TParamIn, TParamOut> where TParamIn : class
|
public abstract class EventHandlerConnector<TParamIn, TParamOut> : ChannelHandlerAdapter, IConnectorWithController<TParamIn, TParamOut> where TParamIn : class
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// 数据返回代理参数
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public delegate MessageReturnCallbackArgs<TParamIn> MessageReturnDelegate(object sender, MessageReturnArgs<TParamOut> args);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 数据返回代理
|
/// 数据返回代理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event MessageReturnDelegate MessageReturn;
|
public Func<MessageReturnArgs<TParamOut>, MessageReturnCallbackArgs<TParamIn>> MessageReturn { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void AddController(IController controller)
|
public void AddController(IController controller)
|
||||||
@@ -84,7 +76,7 @@ namespace Modbus.Net
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected TParamIn InvokeReturnMessage(TParamOut receiveMessage)
|
protected TParamIn InvokeReturnMessage(TParamOut receiveMessage)
|
||||||
{
|
{
|
||||||
return MessageReturn?.Invoke(this, new MessageReturnArgs<TParamOut> { ReturnMessage = receiveMessage })?.SendMessage;
|
return MessageReturn?.Invoke(new MessageReturnArgs<TParamOut> { ReturnMessage = receiveMessage })?.SendMessage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
using Quartz.Logging;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Quartz.Logging;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|||||||
@@ -36,5 +36,34 @@ namespace Modbus.Net
|
|||||||
}
|
}
|
||||||
throw new NotImplementedException(controllerName + " not found exception");
|
throw new NotImplementedException(controllerName + " not found exception");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加一个Controller
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="protocolLinker">ProtocolLinker实例</param>
|
||||||
|
/// <param name="constructorParams">参数</param>
|
||||||
|
/// <param name="connector">Connector实例</param>
|
||||||
|
/// <exception cref="NotImplementedException">如果没有发现控制器,报错</exception>
|
||||||
|
public static void AddController(this IProtocolReceiver<byte[], byte[]> protocolReceiver, object[] constructorParams, IConnector<byte[], byte[]> connector)
|
||||||
|
{
|
||||||
|
IController controller = null;
|
||||||
|
var assemblies = AssemblyHelper.GetAllLibraryAssemblies();
|
||||||
|
string controllerName = protocolReceiver.GetType().Name.Substring(0, protocolReceiver.GetType().Name.Length - 16) + "ResponseController";
|
||||||
|
foreach (var assembly in assemblies)
|
||||||
|
{
|
||||||
|
var controllerType = assembly.GetType(assembly.GetName().Name + "." + controllerName);
|
||||||
|
if (controllerType != null)
|
||||||
|
{
|
||||||
|
controller = assembly.CreateInstance(controllerType.FullName, true, BindingFlags.Default, null, constructorParams, null, null) as IController;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (controller != null)
|
||||||
|
{
|
||||||
|
((IConnectorWithController<byte[], byte[]>)connector).AddController(controller);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new NotImplementedException(controllerName + " not found exception");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Modbus.Net
|
namespace Modbus.Net
|
||||||
@@ -5,8 +6,13 @@ namespace Modbus.Net
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 基础的协议连接接口
|
/// 基础的协议连接接口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IConnector<in TParamIn, TParamOut>
|
public interface IConnector<TParamIn, TParamOut>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 数据返回代理
|
||||||
|
/// </summary>
|
||||||
|
Func<MessageReturnArgs<TParamOut>, MessageReturnCallbackArgs<TParamIn>> MessageReturn { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标识Connector的连接关键字
|
/// 标识Connector的连接关键字
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 基础的协议连接接口
|
/// 基础的协议连接接口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IConnectorWithController<in TParamIn, TParamOut> : IConnector<TParamIn, TParamOut>
|
public interface IConnectorWithController<TParamIn, TParamOut> : IConnector<TParamIn, TParamOut>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 增加传输控制器
|
/// 增加传输控制器
|
||||||
|
|||||||
31
Modbus.Net/Modbus.Net/Interface/IMachineServerMethod.cs
Normal file
31
Modbus.Net/Modbus.Net/Interface/IMachineServerMethod.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Modbus.Net.Interface
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Machine的数据读写接口
|
||||||
|
/// </summary>
|
||||||
|
public interface IMachineServerMethodDatas : IMachineMethod
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 从站发送事件
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler ServerMessageEvent;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 读取数据
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>从设备读取的数据</returns>
|
||||||
|
Task<ReturnStruct<Dictionary<string, ReturnUnit<double>>>> ServerReadDatasAsync(MachineDataType getDataType);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 写入数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="setDataType">写入类型</param>
|
||||||
|
/// <param name="values">需要写入的数据字典,当写入类型为Address时,键为需要写入的地址,当写入类型为CommunicationTag时,键为需要写入的单元的描述</param>
|
||||||
|
/// <returns>是否写入成功</returns>
|
||||||
|
Task<ReturnStruct<bool>> ServerUploadDatasAsync(MachineDataType setDataType, Dictionary<string, double> values);
|
||||||
|
}
|
||||||
|
}
|
||||||
61
Modbus.Net/Modbus.Net/Interface/IProtocolReceiver.cs
Normal file
61
Modbus.Net/Modbus.Net/Interface/IProtocolReceiver.cs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Modbus.Net
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 协议接收器接口
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TParamIn">从Receiver传出的数据类型</typeparam>
|
||||||
|
/// <typeparam name="TParamOut">向Receiver传入的数据类型</typeparam>
|
||||||
|
public interface IProtocolReceiver<TParamIn, TParamOut>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 转发事件
|
||||||
|
/// </summary>
|
||||||
|
Func<TParamOut, TParamIn> DispatchEvent { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 通讯字符串
|
||||||
|
/// </summary>
|
||||||
|
string ConnectionToken { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设备是否连接
|
||||||
|
/// </summary>
|
||||||
|
bool IsConnected { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 连接设备
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>设备是否连接成功</returns>
|
||||||
|
Task<bool> ConnectAsync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 断开设备
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>设备是否断开成功</returns>
|
||||||
|
bool Disconnect();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 接收并发送数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="content">接收协议的内容</param>
|
||||||
|
/// <returns>发送协议的内容</returns>
|
||||||
|
TParamIn ReceiveSend(TParamOut content);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 接收并发送数据,不进行协议扩展和收缩,用于特殊协议
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="content">发送协议的内容</param>
|
||||||
|
/// <returns>接收协议的内容</returns>
|
||||||
|
TParamIn ReceiveSendWithoutExtAndDec(TParamOut content);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查接收的数据是否正确
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="content">接收协议的内容</param>
|
||||||
|
/// <returns>协议是否是正确的</returns>
|
||||||
|
bool? CheckRight(TParamOut content);
|
||||||
|
}
|
||||||
|
}
|
||||||
9
Modbus.Net/Modbus.Net/Interface/IUtilityServer.cs
Normal file
9
Modbus.Net/Modbus.Net/Interface/IUtilityServer.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Modbus.Net
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Api入口的抽象
|
||||||
|
/// </summary>
|
||||||
|
public interface IUtilityServer : IUtilityProperty, IUtilityServerMethodDatas
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
33
Modbus.Net/Modbus.Net/Interface/IUtilityServerMethod.cs
Normal file
33
Modbus.Net/Modbus.Net/Interface/IUtilityServerMethod.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Modbus.Net
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Utility方法读写接口
|
||||||
|
/// </summary>
|
||||||
|
public interface IUtilityServerMethod
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Utility的数据读写接口
|
||||||
|
/// </summary>
|
||||||
|
public interface IUtilityServerMethodDatas : IUtilityServerMethod
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="startAddress">开始地址</param>
|
||||||
|
/// <param name="getByteCount">获取字节数个数</param>
|
||||||
|
/// <returns>接收到的byte数据</returns>
|
||||||
|
Task<ReturnStruct<byte[]>> GetServerDatasAsync(string startAddress, int getByteCount);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="startAddress">开始地址</param>
|
||||||
|
/// <param name="setContents">设置数据</param>
|
||||||
|
/// <returns>是否设置成功</returns>
|
||||||
|
Task<ReturnStruct<bool>> SetServerDatasAsync(string startAddress, object[] setContents);
|
||||||
|
}
|
||||||
|
}
|
||||||
216
Modbus.Net/Modbus.Net/Linker/ProtocolReceiver.cs
Normal file
216
Modbus.Net/Modbus.Net/Linker/ProtocolReceiver.cs
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO.Ports;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Modbus.Net
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 基本的协议连接器
|
||||||
|
/// </summary>
|
||||||
|
public abstract class ProtocolReceiver : ProtocolReceiver<byte[], byte[]>
|
||||||
|
{
|
||||||
|
protected ProtocolReceiver(string com, int slaveAddress, BaudRate? baudRate = null, Parity? parity = null, StopBits? stopBits = null, DataBits? dataBits = null, Handshake? handshake = null,
|
||||||
|
int? connectionTimeout = null, bool? isFullDuplex = null)
|
||||||
|
{
|
||||||
|
baudRate = Enum.Parse<BaudRate>(baudRate != null ? baudRate.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "BaudRate"));
|
||||||
|
parity = Enum.Parse<Parity>(parity != null ? parity.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "Parity"));
|
||||||
|
stopBits = Enum.Parse<StopBits>(stopBits != null ? stopBits.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "StopBits"));
|
||||||
|
dataBits = Enum.Parse<DataBits>(dataBits != null ? dataBits.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "DataBits"));
|
||||||
|
handshake = Enum.Parse<Handshake>(handshake != null ? handshake.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "Handshake"));
|
||||||
|
connectionTimeout = int.Parse(connectionTimeout != null ? connectionTimeout.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "ConnectionTimeout"));
|
||||||
|
isFullDuplex = bool.Parse(isFullDuplex != null ? isFullDuplex.ToString() : null ?? ConfigurationReader.GetValue("COM:" + com, "FullDuplex"));
|
||||||
|
BaseConnector = new ComConnector(com + ":" + slaveAddress, baudRate.Value, parity.Value, stopBits.Value, dataBits.Value, handshake.Value, connectionTimeout.Value, isFullDuplex.Value);
|
||||||
|
var noResponse = bool.Parse(ConfigurationReader.GetValue("COM:" + com, "NoResponse") ?? ConfigurationReader.GetValue("Controller", "NoResponse"));
|
||||||
|
if (noResponse)
|
||||||
|
{
|
||||||
|
((IConnectorWithController<byte[], byte[]>)BaseConnector).AddController(new NoResponseController(int.Parse(ConfigurationReader.GetValue("COM:" + com + ":" + slaveAddress, "FetchSleepTime"))));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.AddController(new object[2] { com, slaveAddress }, BaseConnector);
|
||||||
|
}
|
||||||
|
BaseConnector.MessageReturn = receiveMessage => new MessageReturnCallbackArgs<byte[]>() { SendMessage = ReceiveSend(receiveMessage.ReturnMessage) };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 发送并接收数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="content">发送协议的内容</param>
|
||||||
|
/// <returns>接收协议的内容</returns>
|
||||||
|
public override byte[] ReceiveSend(byte[] content)
|
||||||
|
{
|
||||||
|
var checkRight = CheckRight(content);
|
||||||
|
if (checkRight == true)
|
||||||
|
{
|
||||||
|
var decBytes = BytesDecact(content);
|
||||||
|
var explainContent = DataExplain(decBytes);
|
||||||
|
var returnBytes = DataProcess(explainContent);
|
||||||
|
var extBytes = BytesExtend(returnBytes);
|
||||||
|
return extBytes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 协议内容扩展,发送时根据需要扩展
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="content">扩展前的基本协议内容</param>
|
||||||
|
/// <returns>扩展后的协议内容</returns>
|
||||||
|
public virtual byte[] BytesExtend(byte[] content)
|
||||||
|
{
|
||||||
|
//自动查找相应的协议放缩类,命令规则为——当前的实际类名(注意是继承后的)+"BytesExtend"。
|
||||||
|
var bytesExtend =
|
||||||
|
Activator.CreateInstance(GetType().GetTypeInfo().Assembly.GetType(GetType().FullName + "BytesExtend"))
|
||||||
|
as
|
||||||
|
IProtocolLinkerBytesExtend<byte[], byte[]>;
|
||||||
|
return bytesExtend?.BytesExtend(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 协议内容缩减,接收时根据需要缩减
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="content">缩减前的完整协议内容</param>
|
||||||
|
/// <returns>缩减后的协议内容</returns>
|
||||||
|
public virtual byte[] BytesDecact(byte[] content)
|
||||||
|
{
|
||||||
|
//自动查找相应的协议放缩类,命令规则为——当前的实际类名(注意是继承后的)+"BytesExtend"。
|
||||||
|
var bytesExtend =
|
||||||
|
Activator.CreateInstance(GetType().GetTypeInfo().Assembly.GetType(GetType().FullName + "BytesExtend"))
|
||||||
|
as
|
||||||
|
IProtocolLinkerBytesExtend<byte[], byte[]>;
|
||||||
|
return bytesExtend?.BytesDecact(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查接收的数据是否正确
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="content">接收协议的内容</param>
|
||||||
|
/// <returns>协议是否是正确的</returns>
|
||||||
|
public override bool? CheckRight(byte[] content)
|
||||||
|
{
|
||||||
|
if (content == null)
|
||||||
|
{
|
||||||
|
Disconnect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (content.Length == 0) return null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Func<byte[], ReceiveDataDef> DataExplain { get; }
|
||||||
|
|
||||||
|
public Func<ReceiveDataDef, byte[]> DataProcess { get; set; } = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class ProtocolReceiver<TParamIn, TParamOut> : IProtocolReceiver<TParamIn, TParamOut>
|
||||||
|
where TParamIn : class
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 传输连接器
|
||||||
|
/// </summary>
|
||||||
|
protected IConnector<TParamIn, TParamOut> BaseConnector;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 连接设备
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>设备是否连接成功</returns>
|
||||||
|
public async Task<bool> ConnectAsync()
|
||||||
|
{
|
||||||
|
return await BaseConnector.ConnectAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 断开设备
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>设备是否断开成功</returns>
|
||||||
|
public bool Disconnect()
|
||||||
|
{
|
||||||
|
return BaseConnector.Disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 通讯字符串
|
||||||
|
/// </summary>
|
||||||
|
public string ConnectionToken => BaseConnector.ConnectionToken;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设备是否连接
|
||||||
|
/// </summary>
|
||||||
|
public bool IsConnected => BaseConnector != null && BaseConnector.IsConnected;
|
||||||
|
|
||||||
|
public virtual Func<TParamOut, TParamIn> DispatchEvent
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return receiveContent => ReceiveSend(receiveContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 发送并接收数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="content">发送协议的内容</param>
|
||||||
|
/// <returns>接收协议的内容</returns>
|
||||||
|
public virtual TParamIn ReceiveSend(TParamOut content)
|
||||||
|
{
|
||||||
|
return ReceiveSendWithoutExtAndDec(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 发送并接收数据,不进行协议扩展和收缩,用于特殊协议
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="content">发送协议的内容</param>
|
||||||
|
/// <returns>接收协议的内容</returns>
|
||||||
|
public virtual TParamIn ReceiveSendWithoutExtAndDec(TParamOut content)
|
||||||
|
{
|
||||||
|
var checkRight = CheckRight(content);
|
||||||
|
if (checkRight == true)
|
||||||
|
{
|
||||||
|
if (DispatchEvent != null)
|
||||||
|
{
|
||||||
|
var returnContent = DispatchEvent(content);
|
||||||
|
return returnContent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查接收的数据是否正确
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="content">接收协议的内容</param>
|
||||||
|
/// <returns>协议是否是正确的</returns>
|
||||||
|
public virtual bool? CheckRight(TParamOut content)
|
||||||
|
{
|
||||||
|
if (content != null) return true;
|
||||||
|
Disconnect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ReceiveDataDef
|
||||||
|
{
|
||||||
|
public byte SlaveAddress { get; set; }
|
||||||
|
|
||||||
|
public byte FunctionCode { get; set; }
|
||||||
|
|
||||||
|
public ushort StartAddress { get; set; }
|
||||||
|
|
||||||
|
public ushort Count { get; set; }
|
||||||
|
|
||||||
|
public byte WriteByteCount { get; set; }
|
||||||
|
|
||||||
|
public byte[] WriteContent { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
6
Modbus.Net/Modbus.Net/Machine/BaseServer.cs
Normal file
6
Modbus.Net/Modbus.Net/Machine/BaseServer.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Modbus.Net.Machine
|
||||||
|
{
|
||||||
|
public class BaseServer
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,6 +39,7 @@
|
|||||||
<PackageReference Include="DotNetty.Handlers" Version="0.7.5" />
|
<PackageReference Include="DotNetty.Handlers" Version="0.7.5" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.4" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.4" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
|
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
|
||||||
<PackageReference Include="Quartz" Version="3.6.3" />
|
<PackageReference Include="Quartz" Version="3.6.3" />
|
||||||
<PackageReference Include="System.IO.Ports" Version="7.0.0" />
|
<PackageReference Include="System.IO.Ports" Version="7.0.0" />
|
||||||
|
|||||||
120
Modbus.Net/Modbus.Net/Utility/BaseUtilityServer.cs
Normal file
120
Modbus.Net/Modbus.Net/Utility/BaseUtilityServer.cs
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Modbus.Net
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 基础Api入口
|
||||||
|
/// </summary>
|
||||||
|
public abstract class BaseUtilityServer<TParamIn, TParamOut, TProtocolUnit, TPipeUnit> : IUtilityServer
|
||||||
|
where TProtocolUnit : class, IProtocolFormatting<TParamIn, TParamOut> where TParamOut : class
|
||||||
|
where TPipeUnit : PipeUnit<TParamIn, TParamOut, IProtocolLinker<TParamIn, TParamOut>, TProtocolUnit>
|
||||||
|
{
|
||||||
|
private static readonly ILogger<BaseUtilityServer<TParamIn, TParamOut, TProtocolUnit, TPipeUnit>> logger = LogProvider.CreateLogger<BaseUtilityServer<TParamIn, TParamOut, TProtocolUnit, TPipeUnit>>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 协议收发主体
|
||||||
|
/// </summary>
|
||||||
|
protected IProtocol<TParamIn, TParamOut, TProtocolUnit, TPipeUnit> Wrapper;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造器
|
||||||
|
/// </summary>
|
||||||
|
protected BaseUtilityServer(byte slaveAddress, byte masterAddress)
|
||||||
|
{
|
||||||
|
SlaveAddress = slaveAddress;
|
||||||
|
MasterAddress = masterAddress;
|
||||||
|
AddressTranslator = new AddressTranslatorBase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 连接字符串
|
||||||
|
/// </summary>
|
||||||
|
protected string ConnectionString { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从站号
|
||||||
|
/// </summary>
|
||||||
|
public byte SlaveAddress { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 主站号
|
||||||
|
/// </summary>
|
||||||
|
public byte MasterAddress { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="startAddress">开始地址</param>
|
||||||
|
/// <param name="getByteCount">获取字节数个数</param>
|
||||||
|
/// <returns>接收到的byte数据</returns>
|
||||||
|
public abstract Task<ReturnStruct<byte[]>> GetServerDatasAsync(string startAddress, int getByteCount);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="startAddress">开始地址</param>
|
||||||
|
/// <param name="setContents">设置数据</param>
|
||||||
|
/// <returns>是否设置成功</returns>
|
||||||
|
public abstract Task<ReturnStruct<bool>> SetServerDatasAsync(string startAddress, object[] setContents);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 协议是否遵循小端格式
|
||||||
|
/// </summary>
|
||||||
|
public abstract Endian Endian { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设备是否已经连接
|
||||||
|
/// </summary>
|
||||||
|
public bool IsConnected => Wrapper?.ProtocolLinker != null && Wrapper.ProtocolLinker.IsConnected;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 标识设备的连接关键字
|
||||||
|
/// </summary>
|
||||||
|
public string ConnectionToken
|
||||||
|
=> Wrapper?.ProtocolLinker == null ? ConnectionString : Wrapper.ProtocolLinker.ConnectionToken;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 地址翻译器
|
||||||
|
/// </summary>
|
||||||
|
public AddressTranslator AddressTranslator { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 连接设备
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>设备是否连接成功</returns>
|
||||||
|
public async Task<bool> ConnectAsync()
|
||||||
|
{
|
||||||
|
return await Wrapper.ConnectAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 断开设备
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>设备是否断开成功</returns>
|
||||||
|
public bool Disconnect()
|
||||||
|
{
|
||||||
|
return Wrapper.Disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回Utility的方法集合
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TUtilityMethod">Utility方法集合类型</typeparam>
|
||||||
|
/// <returns>Utility方法集合</returns>
|
||||||
|
public TUtilityMethod GetUtilityMethods<TUtilityMethod>() where TUtilityMethod : class, IUtilityMethod
|
||||||
|
{
|
||||||
|
if (this is TUtilityMethod)
|
||||||
|
{
|
||||||
|
return this as TUtilityMethod;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置连接类型
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="connectionType">连接类型</param>
|
||||||
|
public abstract void SetConnectionType(int connectionType);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -135,15 +135,15 @@ namespace MachineJob.Service
|
|||||||
|
|
||||||
return values.MapGetValuesToSetValues();
|
return values.MapGetValuesToSetValues();
|
||||||
}
|
}
|
||||||
else if(dataReturnDef.ReturnValues.IsSuccess == null)
|
else if (dataReturnDef.ReturnValues.IsSuccess == null)
|
||||||
{
|
{
|
||||||
Random r = new Random();
|
Random r = new Random();
|
||||||
|
|
||||||
Dictionary<string, double> ans = new Dictionary<string, double>();
|
Dictionary<string, double> ans = new Dictionary<string, double>();
|
||||||
|
|
||||||
for (int i = 0; i< 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
ans["Test" + (i+1)] = r.Next(65536) - 32768;
|
ans["Test" + (i + 1)] = r.Next(65536) - 32768;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ans;
|
return ans;
|
||||||
|
|||||||
36
Samples/ModbusTcpToRtu/ConsoleLogProvider.cs
Normal file
36
Samples/ModbusTcpToRtu/ConsoleLogProvider.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using Quartz.Logging;
|
||||||
|
|
||||||
|
namespace ModbusTcpToRtu
|
||||||
|
{
|
||||||
|
// simple log provider to get something to the console
|
||||||
|
public class ConsoleLogProvider : ILogProvider
|
||||||
|
{
|
||||||
|
private readonly IConfigurationRoot configuration = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("appsettings.json")
|
||||||
|
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? "Production"}.json", true)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
public Logger GetLogger(string name)
|
||||||
|
{
|
||||||
|
return (level, func, exception, parameters) =>
|
||||||
|
{
|
||||||
|
if (level >= configuration.GetSection("Quartz").GetValue<Quartz.Logging.LogLevel>("LogLevel") && func != null)
|
||||||
|
{
|
||||||
|
Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + level + "] " + func(), parameters);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDisposable OpenNestedContext(string message)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDisposable OpenMappedContext(string key, object value, bool destructure = false)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
23
Samples/ModbusTcpToRtu/ModbusTcpToRtu.csproj
Normal file
23
Samples/ModbusTcpToRtu/ModbusTcpToRtu.csproj
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Worker">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<UserSecretsId>dotnet-ModbusTcpToRtu-b7b7d9ed-80ce-4790-86de-5c3cf21e0a2e</UserSecretsId>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="7.0.1" />
|
||||||
|
<PackageReference Include="Serilog.Extensions.Logging" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Modbus.Net\Modbus.Net.Modbus\Modbus.Net.Modbus.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Modbus.Net\Modbus.Net\Modbus.Net.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
38
Samples/ModbusTcpToRtu/Program.cs
Normal file
38
Samples/ModbusTcpToRtu/Program.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using ModbusTcpToRtu;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
IHost host = Host.CreateDefaultBuilder(args).UseWindowsService()
|
||||||
|
.ConfigureAppConfiguration((hostingContext, config) =>
|
||||||
|
{
|
||||||
|
var configuration = config
|
||||||
|
.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
|
||||||
|
.AddJsonFile("appsettings.json")
|
||||||
|
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? "Production"}.json", true)
|
||||||
|
.AddEnvironmentVariables()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
Directory.SetCurrentDirectory(hostingContext.HostingEnvironment.ContentRootPath);
|
||||||
|
|
||||||
|
Log.Logger = new LoggerConfiguration()
|
||||||
|
.ReadFrom.Configuration(configuration)
|
||||||
|
.Enrich.FromLogContext()
|
||||||
|
.WriteTo.Console()
|
||||||
|
.WriteTo.File("Log\\log..txt", Serilog.Events.LogEventLevel.Error, shared: true, rollingInterval: RollingInterval.Day)
|
||||||
|
.CreateLogger();
|
||||||
|
|
||||||
|
var loggerFactory = new LoggerFactory().AddSerilog(Log.Logger);
|
||||||
|
|
||||||
|
Quartz.Logging.LogProvider.SetCurrentLogProvider(new ConsoleLogProvider());
|
||||||
|
Modbus.Net.LogProvider.SetLogProvider(loggerFactory);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.ConfigureServices(services =>
|
||||||
|
{
|
||||||
|
services.AddHostedService<Worker>();
|
||||||
|
|
||||||
|
services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(Log.Logger, true));
|
||||||
|
})
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
await host.RunAsync();
|
||||||
|
|
||||||
163
Samples/ModbusTcpToRtu/Worker.cs
Normal file
163
Samples/ModbusTcpToRtu/Worker.cs
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
using Modbus.Net;
|
||||||
|
using Modbus.Net.Modbus;
|
||||||
|
using Quartz;
|
||||||
|
using Quartz.Impl;
|
||||||
|
using Quartz.Impl.Matchers;
|
||||||
|
using BaseUtility = Modbus.Net.BaseUtility<byte[], byte[], Modbus.Net.ProtocolUnit<byte[], byte[]>, Modbus.Net.PipeUnit>;
|
||||||
|
using MultipleMachinesJobScheduler = Modbus.Net.MultipleMachinesJobScheduler<Modbus.Net.IMachineMethodDatas, string, double>;
|
||||||
|
|
||||||
|
namespace ModbusTcpToRtu
|
||||||
|
{
|
||||||
|
public class Worker : BackgroundService
|
||||||
|
{
|
||||||
|
private readonly ILogger<Worker> _logger;
|
||||||
|
|
||||||
|
private BaseUtility readUtility;
|
||||||
|
|
||||||
|
private BaseUtility writeUtility;
|
||||||
|
|
||||||
|
public Worker(ILogger<Worker> logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
|
{
|
||||||
|
var triggerKey = "Modbus.Net.Job.Utility.SchedulerTrigger";
|
||||||
|
var jobKey = "Modbus.Net.Job.Utility.JobKey";
|
||||||
|
|
||||||
|
var intervalMilliSecond = int.Parse(ConfigurationReader.GetValue("Utility", "interval")) * 1000;
|
||||||
|
var count = int.Parse(ConfigurationReader.GetValue("Utility", "count"));
|
||||||
|
|
||||||
|
var readWriteGroup = ConfigurationReader.GetContent<List<ReadWriteGroup>>("Utility", "readwrite");
|
||||||
|
|
||||||
|
var readType = Enum.Parse<ModbusType>(ConfigurationReader.GetValue("Utility:read", "type"));
|
||||||
|
var readAddress = ConfigurationReader.GetValue("Utility:read", "address");
|
||||||
|
var readSlaveAddress = byte.Parse(ConfigurationReader.GetValue("Utility:read", "slaveAddress"));
|
||||||
|
var readMasterAddress = byte.Parse(ConfigurationReader.GetValue("Utility:read", "masterAddress"));
|
||||||
|
var writeType = Enum.Parse<ModbusType>(ConfigurationReader.GetValue("Utility:write", "type"));
|
||||||
|
var writeAddress = ConfigurationReader.GetValue("Utility:write", "address");
|
||||||
|
var writeSlaveAddress = byte.Parse(ConfigurationReader.GetValue("Utility:write", "slaveAddress"));
|
||||||
|
var writeMasterAddress = byte.Parse(ConfigurationReader.GetValue("Utility:write", "masterAddress"));
|
||||||
|
|
||||||
|
readUtility = new ModbusUtility(readType, readAddress, readSlaveAddress, readMasterAddress, Endian.BigEndianLsb);
|
||||||
|
writeUtility = new ModbusUtility(writeType, writeAddress, writeSlaveAddress, writeMasterAddress, Endian.BigEndianLsb);
|
||||||
|
|
||||||
|
IScheduler scheduler = await StdSchedulerFactory.GetDefaultScheduler();
|
||||||
|
|
||||||
|
await scheduler.Start();
|
||||||
|
|
||||||
|
ITrigger trigger;
|
||||||
|
if (intervalMilliSecond <= 0)
|
||||||
|
{
|
||||||
|
trigger = TriggerBuilder.Create()
|
||||||
|
.WithIdentity(triggerKey, "Modbus.Net.DataQuery.Group." + triggerKey)
|
||||||
|
.StartNow()
|
||||||
|
.Build();
|
||||||
|
}
|
||||||
|
else if (count >= 0)
|
||||||
|
trigger = TriggerBuilder.Create()
|
||||||
|
.WithIdentity(triggerKey, "Modbus.Net.DataQuery.Group." + triggerKey)
|
||||||
|
.StartNow()
|
||||||
|
.WithSimpleSchedule(b => b.WithInterval(TimeSpan.FromMilliseconds(intervalMilliSecond)).WithRepeatCount(count))
|
||||||
|
.Build();
|
||||||
|
else
|
||||||
|
trigger = TriggerBuilder.Create()
|
||||||
|
.WithIdentity(triggerKey, "Modbus.Net.DataQuery.Group." + triggerKey)
|
||||||
|
.StartNow()
|
||||||
|
.WithSimpleSchedule(b => b.WithInterval(TimeSpan.FromMilliseconds(intervalMilliSecond)).RepeatForever())
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
IJobListener listener;
|
||||||
|
if (intervalMilliSecond <= 0)
|
||||||
|
{
|
||||||
|
listener = new JobChainingJobLIstenerWithDataMapRepeated("Modbus.Net.DataQuery.Chain." + triggerKey, new string[2] { "Value", "SetValue" }, count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
listener = new JobChainingJobListenerWithDataMap("Modbus.Net.DataQuery.Chain." + triggerKey, new string[2] { "Value", "SetValue" });
|
||||||
|
}
|
||||||
|
scheduler.ListenerManager.AddJobListener(listener, GroupMatcher<JobKey>.GroupEquals("Modbus.Net.DataQuery.Group." + triggerKey));
|
||||||
|
|
||||||
|
if (await scheduler.GetTrigger(new TriggerKey(triggerKey)) != null)
|
||||||
|
{
|
||||||
|
await scheduler.UnscheduleJob(new TriggerKey(triggerKey, "Modbus.Net.DataQuery.Group." + triggerKey));
|
||||||
|
}
|
||||||
|
var jobKeys = await scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupEquals("Modbus.Net.DataQuery.Group." + triggerKey));
|
||||||
|
await scheduler.DeleteJobs(jobKeys);
|
||||||
|
|
||||||
|
var job = JobBuilder.Create<UtilityPassDataJob>()
|
||||||
|
.WithIdentity(jobKey)
|
||||||
|
.StoreDurably(true)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
job.JobDataMap.Put("UtilityRead", readUtility);
|
||||||
|
job.JobDataMap.Put("UtilityReadWriteGroup", readWriteGroup);
|
||||||
|
job.JobDataMap.Put("UtilityWrite", writeUtility);
|
||||||
|
|
||||||
|
await scheduler.ScheduleJob(job, trigger);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task StopAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return Task.Run(() => MultipleMachinesJobScheduler.CancelJob());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UtilityPassDataJob : IJob
|
||||||
|
{
|
||||||
|
public async Task Execute(IJobExecutionContext context)
|
||||||
|
{
|
||||||
|
object utilityReadObject;
|
||||||
|
object utilityWriteObject;
|
||||||
|
object utilityReadWriteGroupObject;
|
||||||
|
|
||||||
|
context.JobDetail.JobDataMap.TryGetValue("UtilityRead", out utilityReadObject);
|
||||||
|
context.JobDetail.JobDataMap.TryGetValue("UtilityWrite", out utilityWriteObject);
|
||||||
|
context.JobDetail.JobDataMap.TryGetValue("UtilityReadWriteGroup", out utilityReadWriteGroupObject);
|
||||||
|
|
||||||
|
var readUtility = (BaseUtility)utilityReadObject;
|
||||||
|
var writeUtility = (BaseUtility)utilityWriteObject;
|
||||||
|
var utilityReadWriteGroup = (List<ReadWriteGroup>)utilityReadWriteGroupObject;
|
||||||
|
|
||||||
|
if (readUtility.IsConnected != true)
|
||||||
|
await readUtility.ConnectAsync();
|
||||||
|
if (writeUtility.IsConnected != true)
|
||||||
|
await writeUtility.ConnectAsync();
|
||||||
|
foreach (var rwGroup in utilityReadWriteGroup)
|
||||||
|
{
|
||||||
|
var datas = await readUtility.GetDatasAsync(rwGroup.ReadStart / 10000 + "X " + rwGroup.ReadStart % 10000, rwGroup.ReadCount * 2);
|
||||||
|
if (datas.IsSuccess == true)
|
||||||
|
{
|
||||||
|
var ans = await writeUtility.SetDatasAsync(rwGroup.WriteStart / 10000 + "X " + rwGroup.WriteStart % 10000, ByteArrayToObjectArray(datas.Datas));
|
||||||
|
if (ans.Datas)
|
||||||
|
{
|
||||||
|
Console.WriteLine("success");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static object[] ByteArrayToObjectArray(byte[] arrBytes)
|
||||||
|
{
|
||||||
|
List<object> objArray = new List<object>();
|
||||||
|
foreach (byte b in arrBytes)
|
||||||
|
{
|
||||||
|
objArray.Add(b);
|
||||||
|
}
|
||||||
|
return objArray.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ReadWriteGroup
|
||||||
|
{
|
||||||
|
public int ReadStart { get; set; }
|
||||||
|
public int ReadCount { get; set; }
|
||||||
|
public int WriteStart { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
8
Samples/ModbusTcpToRtu/appsettings.Development.json
Normal file
8
Samples/ModbusTcpToRtu/appsettings.Development.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
53
Samples/ModbusTcpToRtu/appsettings.default.json
Normal file
53
Samples/ModbusTcpToRtu/appsettings.default.json
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"Modbus.Net": {
|
||||||
|
"TCP": {
|
||||||
|
"ConnectionTimeout": "5000",
|
||||||
|
"FetchSleepTime": "100",
|
||||||
|
"FullDuplex": "True",
|
||||||
|
"Modbus": {
|
||||||
|
"ModbusPort": "502",
|
||||||
|
"IP": "192.168.1.1"
|
||||||
|
},
|
||||||
|
"Siemens": {
|
||||||
|
"SiemensPort": "102",
|
||||||
|
"IP": "192.168.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"UDP": {
|
||||||
|
"ConnectionTimeout": "5000",
|
||||||
|
"FetchSleepTime": "100",
|
||||||
|
"FullDuplex": "True",
|
||||||
|
"Modbus": {
|
||||||
|
"ModbusPort": "502",
|
||||||
|
"IP": "192.168.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"COM": {
|
||||||
|
"FetchSleepTime": "100",
|
||||||
|
"ConnectionTimeout": "5000",
|
||||||
|
"BaudRate": "BaudRate9600",
|
||||||
|
"Parity": "None",
|
||||||
|
"StopBits": "One",
|
||||||
|
"DataBits": "Eight",
|
||||||
|
"Handshake": "None",
|
||||||
|
"FullDuplex": "False",
|
||||||
|
"Modbus": {
|
||||||
|
"COM": "COM1"
|
||||||
|
},
|
||||||
|
"Siemens": {
|
||||||
|
"COM": "COM2",
|
||||||
|
"Parity": "Even"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"OpcDa": {
|
||||||
|
"Host": "opcda://localhost/test"
|
||||||
|
},
|
||||||
|
"OpcUa": {
|
||||||
|
"Host": "opc.tcp://localhost/test"
|
||||||
|
},
|
||||||
|
"Controller": {
|
||||||
|
"WaitingListCount": "100",
|
||||||
|
"NoResponse": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
55
Samples/ModbusTcpToRtu/appsettings.json
Normal file
55
Samples/ModbusTcpToRtu/appsettings.json
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"Serilog": {
|
||||||
|
"MinimumLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Override": {
|
||||||
|
"Microsoft": "Information",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Information",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Quartz": {
|
||||||
|
"LogLevel": "Info"
|
||||||
|
},
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"DatabaseWriteConnectionString": "Server=127.0.0.1; User ID=root; Password=123456; Database=modbusnettest;"
|
||||||
|
},
|
||||||
|
|
||||||
|
"Modbus.Net": {
|
||||||
|
"Utility": {
|
||||||
|
"interval": 10, //间隔时常(秒)
|
||||||
|
"count": -1, //不要动
|
||||||
|
"readwrite": [
|
||||||
|
{
|
||||||
|
"readStart": 40001, //读取开始地址
|
||||||
|
"readCount": 16, //读取字的个数
|
||||||
|
"writeStart": 40001 //写入开始地址
|
||||||
|
}, //可以写多个
|
||||||
|
{
|
||||||
|
"readStart": 40016, //读取开始地址
|
||||||
|
"readCount": 16, //读取字的个数
|
||||||
|
"writeStart": 40016 //写入开始地址
|
||||||
|
} //可以写多个
|
||||||
|
],
|
||||||
|
"read": {
|
||||||
|
"type": "Tcp",
|
||||||
|
"address": "127.0.0.1:502", //读取的设备地址
|
||||||
|
"slaveAddress": 2, //从站地址
|
||||||
|
"masterAddress": 1 //主站地址
|
||||||
|
},
|
||||||
|
"write": {
|
||||||
|
"type": "Rtu",
|
||||||
|
"address": "COM2", //写入的设备地址
|
||||||
|
"slaveAddress": 3, //从站地址
|
||||||
|
"masterAddress": 1 //主站地址
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
36
Samples/SampleModbusRtuServer/ConsoleLogProvider.cs
Normal file
36
Samples/SampleModbusRtuServer/ConsoleLogProvider.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using Quartz.Logging;
|
||||||
|
|
||||||
|
namespace SampleModbusRtuServer
|
||||||
|
{
|
||||||
|
// simple log provider to get something to the console
|
||||||
|
public class ConsoleLogProvider : ILogProvider
|
||||||
|
{
|
||||||
|
private readonly IConfigurationRoot configuration = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("appsettings.json")
|
||||||
|
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? "Production"}.json", true)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
public Logger GetLogger(string name)
|
||||||
|
{
|
||||||
|
return (level, func, exception, parameters) =>
|
||||||
|
{
|
||||||
|
if (level >= configuration.GetSection("Quartz").GetValue<Quartz.Logging.LogLevel>("LogLevel") && func != null)
|
||||||
|
{
|
||||||
|
Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + level + "] " + func(), parameters);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDisposable OpenNestedContext(string message)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDisposable OpenMappedContext(string key, object value, bool destructure = false)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
34
Samples/SampleModbusRtuServer/DatabaseWrite.cs
Normal file
34
Samples/SampleModbusRtuServer/DatabaseWrite.cs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace MachineJob
|
||||||
|
{
|
||||||
|
public class DatabaseWriteContext : DbContext
|
||||||
|
{
|
||||||
|
private static readonly IConfigurationRoot configuration = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("appsettings.default.json", optional: false, reloadOnChange: true)
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||||
|
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true, reloadOnChange: true)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
private static readonly string connectionString = configuration.GetConnectionString("DatabaseWriteConnectionString")!;
|
||||||
|
|
||||||
|
public DbSet<DatabaseWriteEntity>? DatabaseWrites { get; set; }
|
||||||
|
|
||||||
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
|
{
|
||||||
|
optionsBuilder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Table(name: "databasewrites")]
|
||||||
|
public partial class DatabaseWriteEntity
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public DateTime UpdateTime { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
39
Samples/SampleModbusRtuServer/Program.cs
Normal file
39
Samples/SampleModbusRtuServer/Program.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using SampleModbusRtuServer;
|
||||||
|
using SampleModbusRtuServer.Service;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
IHost host = Host.CreateDefaultBuilder(args).UseWindowsService()
|
||||||
|
.ConfigureAppConfiguration((hostingContext, config) =>
|
||||||
|
{
|
||||||
|
var configuration = config
|
||||||
|
.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
|
||||||
|
.AddJsonFile("appsettings.json")
|
||||||
|
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? "Production"}.json", true)
|
||||||
|
.AddEnvironmentVariables()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
Directory.SetCurrentDirectory(hostingContext.HostingEnvironment.ContentRootPath);
|
||||||
|
|
||||||
|
Log.Logger = new LoggerConfiguration()
|
||||||
|
.ReadFrom.Configuration(configuration)
|
||||||
|
.Enrich.FromLogContext()
|
||||||
|
.WriteTo.Console()
|
||||||
|
.WriteTo.File("Log\\log..txt", Serilog.Events.LogEventLevel.Error, shared: true, rollingInterval: RollingInterval.Day)
|
||||||
|
.CreateLogger();
|
||||||
|
|
||||||
|
var loggerFactory = new LoggerFactory().AddSerilog(Log.Logger);
|
||||||
|
|
||||||
|
Quartz.Logging.LogProvider.SetCurrentLogProvider(new ConsoleLogProvider());
|
||||||
|
Modbus.Net.LogProvider.SetLogProvider(loggerFactory);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.ConfigureServices(services =>
|
||||||
|
{
|
||||||
|
services.AddHostedService<Worker>();
|
||||||
|
|
||||||
|
services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(Log.Logger, true));
|
||||||
|
})
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
await host.RunAsync();
|
||||||
|
|
||||||
59
Samples/SampleModbusRtuServer/SampleModbusRtuServer.csproj
Normal file
59
Samples/SampleModbusRtuServer/SampleModbusRtuServer.csproj
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Worker">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<UserSecretsId>dotnet-SampleModbusRtuServer-b9a42287-9797-4b7f-81e6-0796c51ff8e0</UserSecretsId>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_ContentIncludedByDefault Remove="appsettings.default.json" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.9">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<TreatAsUsed>true</TreatAsUsed>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="7.0.1" />
|
||||||
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Extensions.Logging" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Modbus.Net\Modbus.Net.Modbus\Modbus.Net.Modbus.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Modbus.Net\Modbus.Net.OPC\Modbus.Net.Opc.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Modbus.Net\Modbus.Net.Siemens\Modbus.Net.Siemens.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Modbus.Net\Modbus.Net\Modbus.Net.csproj" />
|
||||||
|
<ProjectReference Include="..\MachineJob.CodeGenerator\MachineJob.CodeGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Update="appsettings.default.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||||
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="appsettings.Development.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||||
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||||
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="appsettings.Production.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||||
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
85
Samples/SampleModbusRtuServer/Worker.cs
Normal file
85
Samples/SampleModbusRtuServer/Worker.cs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
using Modbus.Net.Modbus;
|
||||||
|
using MultipleMachinesJobScheduler = Modbus.Net.MultipleMachinesJobScheduler<Modbus.Net.IMachineMethodDatas, string, double>;
|
||||||
|
|
||||||
|
namespace SampleModbusRtuServer.Service
|
||||||
|
{
|
||||||
|
public class Worker : BackgroundService
|
||||||
|
{
|
||||||
|
private readonly ILogger<Worker> _logger;
|
||||||
|
|
||||||
|
private byte[] threex = new byte[19998];
|
||||||
|
|
||||||
|
public Worker(ILogger<Worker> logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
|
{
|
||||||
|
ModbusRtuProtocolReceiver receiver = new ModbusRtuProtocolReceiver("COM2", 1);
|
||||||
|
receiver.DataProcess = receiveContent =>
|
||||||
|
{
|
||||||
|
byte[] returnBytes = null;
|
||||||
|
var readContent = new byte[receiveContent.Count * 2];
|
||||||
|
var values = receiveContent.WriteContent;
|
||||||
|
if (values != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
/*using (var context = new DatabaseWriteContext())
|
||||||
|
{
|
||||||
|
context.DatabaseWrites?.Add(new DatabaseWriteEntity
|
||||||
|
{
|
||||||
|
Value1 = values["Test1"].DeviceValue,
|
||||||
|
Value2 = values["Test2"].DeviceValue,
|
||||||
|
Value3 = values["Test3"].DeviceValue,
|
||||||
|
Value4 = values["Test4"].DeviceValue,
|
||||||
|
Value5 = values["Test5"].DeviceValue,
|
||||||
|
Value6 = values["Test6"].DeviceValue,
|
||||||
|
Value7 = values["Test7"].DeviceValue,
|
||||||
|
Value8 = values["Test8"].DeviceValue,
|
||||||
|
Value9 = values["Test9"].DeviceValue,
|
||||||
|
Value10 = values["Test10"].DeviceValue,
|
||||||
|
UpdateTime = DateTime.Now,
|
||||||
|
});
|
||||||
|
context.SaveChanges();
|
||||||
|
}*/
|
||||||
|
switch (receiveContent.FunctionCode)
|
||||||
|
{
|
||||||
|
case (byte)ModbusProtocolFunctionCode.WriteMultiRegister:
|
||||||
|
{
|
||||||
|
Array.Copy(receiveContent.WriteContent, 0, threex, receiveContent.StartAddress * 2, receiveContent.Count);
|
||||||
|
returnBytes = new WriteDataModbusProtocol().Format(receiveContent.SlaveAddress, receiveContent.FunctionCode, receiveContent.StartAddress, receiveContent.Count);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (receiveContent.FunctionCode)
|
||||||
|
{
|
||||||
|
case (byte)ModbusProtocolFunctionCode.ReadHoldRegister:
|
||||||
|
{
|
||||||
|
Array.Copy(threex, receiveContent.StartAddress, readContent, 0, readContent.Length);
|
||||||
|
returnBytes = new ReadDataModbusProtocol().Format(receiveContent.SlaveAddress, receiveContent.FunctionCode, (byte)receiveContent.Count, readContent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (returnBytes != null) return returnBytes;
|
||||||
|
else return null;
|
||||||
|
};
|
||||||
|
await receiver.ConnectAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task StopAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return Task.Run(() => MultipleMachinesJobScheduler.CancelJob());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
Samples/SampleModbusRtuServer/appsettings.Development.json
Normal file
21
Samples/SampleModbusRtuServer/appsettings.Development.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"Serilog": {
|
||||||
|
"MinimumLevel": {
|
||||||
|
"Default": "Debug",
|
||||||
|
"Override": {
|
||||||
|
"Microsoft": "Debug",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Debug"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Debug",
|
||||||
|
"Microsoft": "Debug",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Debug"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Quartz": {
|
||||||
|
"LogLevel": "Debug"
|
||||||
|
}
|
||||||
|
}
|
||||||
21
Samples/SampleModbusRtuServer/appsettings.Production.json
Normal file
21
Samples/SampleModbusRtuServer/appsettings.Production.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"Serilog": {
|
||||||
|
"MinimumLevel": {
|
||||||
|
"Default": "Error",
|
||||||
|
"Override": {
|
||||||
|
"Microsoft": "Error",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Error",
|
||||||
|
"Microsoft": "Error",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Quartz": {
|
||||||
|
"LogLevel": "Error"
|
||||||
|
}
|
||||||
|
}
|
||||||
53
Samples/SampleModbusRtuServer/appsettings.default.json
Normal file
53
Samples/SampleModbusRtuServer/appsettings.default.json
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"Modbus.Net": {
|
||||||
|
"TCP": {
|
||||||
|
"ConnectionTimeout": "5000",
|
||||||
|
"FetchSleepTime": "100",
|
||||||
|
"FullDuplex": "True",
|
||||||
|
"Modbus": {
|
||||||
|
"ModbusPort": "502",
|
||||||
|
"IP": "192.168.1.1"
|
||||||
|
},
|
||||||
|
"Siemens": {
|
||||||
|
"SiemensPort": "102",
|
||||||
|
"IP": "192.168.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"UDP": {
|
||||||
|
"ConnectionTimeout": "5000",
|
||||||
|
"FetchSleepTime": "100",
|
||||||
|
"FullDuplex": "True",
|
||||||
|
"Modbus": {
|
||||||
|
"ModbusPort": "502",
|
||||||
|
"IP": "192.168.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"COM": {
|
||||||
|
"FetchSleepTime": "100",
|
||||||
|
"ConnectionTimeout": "5000",
|
||||||
|
"BaudRate": "BaudRate9600",
|
||||||
|
"Parity": "None",
|
||||||
|
"StopBits": "One",
|
||||||
|
"DataBits": "Eight",
|
||||||
|
"Handshake": "None",
|
||||||
|
"FullDuplex": "False",
|
||||||
|
"Modbus": {
|
||||||
|
"COM": "COM1"
|
||||||
|
},
|
||||||
|
"Siemens": {
|
||||||
|
"COM": "COM2",
|
||||||
|
"Parity": "Even"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"OpcDa": {
|
||||||
|
"Host": "opcda://localhost/test"
|
||||||
|
},
|
||||||
|
"OpcUa": {
|
||||||
|
"Host": "opc.tcp://localhost/test"
|
||||||
|
},
|
||||||
|
"Controller": {
|
||||||
|
"WaitingListCount": "100",
|
||||||
|
"NoResponse": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
249
Samples/SampleModbusRtuServer/appsettings.json
Normal file
249
Samples/SampleModbusRtuServer/appsettings.json
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
{
|
||||||
|
"Serilog": {
|
||||||
|
"MinimumLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Override": {
|
||||||
|
"Microsoft": "Information",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Information",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Quartz": {
|
||||||
|
"LogLevel": "Info"
|
||||||
|
},
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"DatabaseWriteConnectionString": "Server=127.0.0.1; User ID=root; Password=123456; Database=modbusnettest;"
|
||||||
|
},
|
||||||
|
|
||||||
|
"Modbus.Net": {
|
||||||
|
"Machine": [
|
||||||
|
{
|
||||||
|
"a:id": "ModbusMachine1",
|
||||||
|
"b:protocol": "Modbus",
|
||||||
|
"c:type": "Tcp",
|
||||||
|
"d:connectionString": "127.0.0.1",
|
||||||
|
"e:addressMap": "AddressMapModbus",
|
||||||
|
"f:keepConnect": true,
|
||||||
|
"g:slaveAddress": 1,
|
||||||
|
"h:masterAddress": 2,
|
||||||
|
"i:endian": "BigEndianLsb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:id": "SiemensMachine1",
|
||||||
|
"b:protocol": "Siemens",
|
||||||
|
"c:type": "Tcp",
|
||||||
|
"d:connectionString": "127.0.0.1",
|
||||||
|
"e:model": "S7_1200",
|
||||||
|
"f:addressMap": "AddressMapSiemens",
|
||||||
|
"g:keepConnect": true,
|
||||||
|
"h:slaveAddress": 1,
|
||||||
|
"i:masterAddress": 2,
|
||||||
|
"j:src": 1,
|
||||||
|
"k:dst": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:id": "ModbusMachine2",
|
||||||
|
"b:protocol": "Modbus",
|
||||||
|
"c:type": "Rtu",
|
||||||
|
"d:connectionString": "COM1",
|
||||||
|
"e:addressMap": "AddressMapModbus",
|
||||||
|
"f:keepConnect": true,
|
||||||
|
"g:slaveAddress": 1,
|
||||||
|
"h:masterAddress": 2,
|
||||||
|
"i:endian": "BigEndianLsb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:id": "SiemensMachine2",
|
||||||
|
"b:protocol": "Siemens",
|
||||||
|
"c:type": "Ppi",
|
||||||
|
"d:connectionString": "COM2",
|
||||||
|
"e:model": "S7_200",
|
||||||
|
"f:addressMap": "AddressMapSiemens",
|
||||||
|
"g:keepConnect": true,
|
||||||
|
"h:slaveAddress": 2,
|
||||||
|
"i:masterAddress": 0,
|
||||||
|
"j:src": 1,
|
||||||
|
"k:dst": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:id": "OpcMachine1",
|
||||||
|
"b:protocol": "Opc",
|
||||||
|
"c:type": "Da",
|
||||||
|
"d:connectionString": "opcda://localhost/Matrikon.OPC.Simulation.1",
|
||||||
|
"e:addressMap": "AddressMapOpc",
|
||||||
|
"f:tagSpliter": "."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"addressMap": {
|
||||||
|
"AddressMapModbus": [
|
||||||
|
{
|
||||||
|
"Area": "4X",
|
||||||
|
"Address": 1,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "1",
|
||||||
|
"Name": "Test1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Area": "4X",
|
||||||
|
"Address": 2,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "2",
|
||||||
|
"Name": "Test2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Area": "4X",
|
||||||
|
"Address": 3,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "3",
|
||||||
|
"Name": "Test3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Area": "4X",
|
||||||
|
"Address": 4,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "4",
|
||||||
|
"Name": "Test4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Area": "4X",
|
||||||
|
"Address": 5,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "5",
|
||||||
|
"Name": "Test5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Area": "4X",
|
||||||
|
"Address": 6,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "6",
|
||||||
|
"Name": "Test6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Area": "4X",
|
||||||
|
"Address": 7,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "7",
|
||||||
|
"Name": "Test7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Area": "4X",
|
||||||
|
"Address": 8,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "8",
|
||||||
|
"Name": "Test8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Area": "4X",
|
||||||
|
"Address": 9,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "9",
|
||||||
|
"Name": "Test9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Area": "4X",
|
||||||
|
"Address": 10,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "10",
|
||||||
|
"Name": "Test10"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"AddressMapSiemens": [
|
||||||
|
{
|
||||||
|
"Area": "DB1",
|
||||||
|
"Address": 0,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "1",
|
||||||
|
"Name": "Test1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Area": "DB1",
|
||||||
|
"Address": 2,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "2",
|
||||||
|
"Name": "Test2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Area": "DB1",
|
||||||
|
"Address": 4,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "3",
|
||||||
|
"Name": "Test3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Area": "DB1",
|
||||||
|
"Address": 6,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "4",
|
||||||
|
"Name": "Test4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Area": "DB1",
|
||||||
|
"Address": 8,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "5",
|
||||||
|
"Name": "Test5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Area": "DB1",
|
||||||
|
"Address": 10,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "6",
|
||||||
|
"Name": "Test6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Area": "DB1",
|
||||||
|
"Address": 12,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "7",
|
||||||
|
"Name": "Test7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Area": "DB1",
|
||||||
|
"Address": 14,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "8",
|
||||||
|
"Name": "Test8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Area": "DB1",
|
||||||
|
"Address": 16,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "9",
|
||||||
|
"Name": "Test9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Area": "DB1",
|
||||||
|
"Address": 18,
|
||||||
|
"DataType": "Int16",
|
||||||
|
"Id": "10",
|
||||||
|
"Name": "Test10"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"AddressMapOpc": [
|
||||||
|
{
|
||||||
|
"Area": "Random",
|
||||||
|
"Address": "Real4",
|
||||||
|
"DataType": "Single",
|
||||||
|
"Id": "1",
|
||||||
|
"Name": "Test1",
|
||||||
|
"DecimalPos": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Area": "Random",
|
||||||
|
"Address": "Real8",
|
||||||
|
"DataType": "Double",
|
||||||
|
"Id": "2",
|
||||||
|
"Name": "Test2",
|
||||||
|
"DecimalPos": 4
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user