mirror of
https://github.com/RRQM/TouchSocket.git
synced 2025-12-21 02:46:43 +08:00
225 lines
7.6 KiB
C#
225 lines
7.6 KiB
C#
//------------------------------------------------------------------------------
|
||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||
// Github源代码仓库:https://github.com/RRQM
|
||
// API首页:https://touchsocket.net/
|
||
// 交流QQ群:234762506
|
||
// 感谢您的下载和使用
|
||
//------------------------------------------------------------------------------
|
||
|
||
using TouchSocket.Core;
|
||
using TouchSocket.Modbus;
|
||
using TouchSocket.SerialPorts;
|
||
using TouchSocket.Sockets;
|
||
|
||
namespace ModbusClientConsoleApp;
|
||
|
||
internal class Program
|
||
{
|
||
private static async Task Main(string[] args)
|
||
{
|
||
var master = await GetModbusTcpMasterAsync();
|
||
|
||
await ReadWriteHoldingRegisters(master);
|
||
Console.ReadKey();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 要测试,请打开Modbus Slave软件,设置HoldingRegisters。至少30个长度。
|
||
/// </summary>
|
||
public static async Task ReadWriteHoldingRegisters(IModbusMaster master)
|
||
{
|
||
//写入单个寄存器
|
||
await master.WriteSingleRegisterAsync(1, 0, 1);//默认short ABCD端序
|
||
await master.WriteSingleRegisterAsync(1, 1, 1000);//默认short ABCD端序
|
||
|
||
using (var valueByteBlock = new ValueByteBlock(1024))
|
||
{
|
||
valueByteBlock.WriteUInt16(2, EndianType.Big);//ABCD端序
|
||
valueByteBlock.WriteUInt16(2000, EndianType.Little);//DCBA端序
|
||
valueByteBlock.WriteInt32(int.MaxValue, EndianType.BigSwap);//BADC端序
|
||
valueByteBlock.WriteInt64(long.MaxValue, EndianType.LittleSwap);//CDAB端序
|
||
|
||
//写入字符串,会先用4字节表示字符串长度,然后按utf8编码写入字符串
|
||
valueByteBlock.WriteString("Hello1");
|
||
|
||
//如果想要直接写入字符串,可以使用WriteNormalString方法
|
||
//valueByteBlock.WriteNormalString("Hello1", System.Text.Encoding.UTF8);
|
||
|
||
//注意:写入字符串时,应当保证写入后的字节总数为双数。如果是单数,则会报错。
|
||
|
||
//写入到寄存器
|
||
await master.WriteMultipleRegistersAsync(1, 2, valueByteBlock.ToArray());
|
||
}
|
||
|
||
//读取寄存器
|
||
var response = await master.ReadHoldingRegistersAsync(1, 0, 30);
|
||
|
||
//创建一个读取器
|
||
var reader = response.CreateReader();
|
||
|
||
Console.WriteLine(reader.ReadInt16(EndianType.Big));
|
||
Console.WriteLine(reader.ReadInt16(EndianType.Big));
|
||
Console.WriteLine(reader.ReadInt16(EndianType.Big));
|
||
Console.WriteLine(reader.ReadInt16(EndianType.Little));
|
||
Console.WriteLine(reader.ReadInt32(EndianType.BigSwap));
|
||
Console.WriteLine(reader.ReadInt64(EndianType.LittleSwap));
|
||
Console.WriteLine(reader.ReadString());
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读写线圈,在测试时,请选择对应的Modbus Slave类型,且调到线圈操作,至少5个长度
|
||
/// </summary>
|
||
/// <param name="master"></param>
|
||
public static async Task ReadWriteCoilsShouldBeOk(IModbusMaster master)
|
||
{
|
||
//写单个线圈
|
||
await master.WriteSingleCoilAsync(1, 0, true);
|
||
await master.WriteSingleCoilAsync(1, 1, false);
|
||
|
||
//写多个线圈
|
||
await master.WriteMultipleCoilsAsync(1, 2, new bool[] { true, false, true });
|
||
|
||
//读取线圈
|
||
var values = await master.ReadCoilsAsync(1, 0, 5);
|
||
foreach (var value in values)
|
||
{
|
||
Console.WriteLine(value);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Tcp协议的主站
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public static async Task<IModbusMaster> GetModbusTcpMasterAsync()
|
||
{
|
||
var client = new ModbusTcpMaster();
|
||
await client.SetupAsync(new TouchSocketConfig()
|
||
.ConfigurePlugins(a =>
|
||
{
|
||
a.UseModbusTcpMasterReconnectionPlugin()
|
||
.UsePolling(TimeSpan.FromSeconds(1));
|
||
}));
|
||
await client.ConnectAsync("127.0.0.1:502");
|
||
return client;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Udp协议的主站
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public static async Task<IModbusMaster> GetModbusUdpMaster()
|
||
{
|
||
var client = new ModbusUdpMaster();
|
||
await client.SetupAsync(new TouchSocketConfig()
|
||
.UseUdpReceive()
|
||
.SetRemoteIPHost("127.0.0.1:502"));
|
||
await client.StartAsync();
|
||
return client;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 串口协议的主站
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public static async Task<IModbusMaster> GetModbusRtuMaster()
|
||
{
|
||
var client = new ModbusRtuMaster();
|
||
await client.SetupAsync(new TouchSocketConfig()
|
||
.SetSerialPortOption(new SerialPortOption()
|
||
{
|
||
BaudRate = 9600,
|
||
DataBits = 8,
|
||
Parity = System.IO.Ports.Parity.Even,
|
||
PortName = "COM2",
|
||
StopBits = System.IO.Ports.StopBits.One
|
||
}));
|
||
await client.ConnectAsync();
|
||
return client;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 基于Tcp协议,但使用Rtu的主站
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public static async Task<IModbusMaster> GetModbusRtuOverTcpMaster()
|
||
{
|
||
var client = new ModbusRtuOverTcpMaster();
|
||
await client.ConnectAsync("127.0.0.1:502");
|
||
return client;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 基于Udp协议,但使用Rtu的主站
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public static async Task<IModbusMaster> GetModbusRtuOverUdpMaster()
|
||
{
|
||
var client = new ModbusRtuOverUdpMaster();
|
||
await client.SetupAsync(new TouchSocketConfig()
|
||
.UseUdpReceive()
|
||
.SetRemoteIPHost("127.0.0.1:502"));
|
||
await client.StartAsync();
|
||
return client;
|
||
}
|
||
}
|
||
|
||
internal class MyClass
|
||
{
|
||
public int P1 { get; set; }
|
||
public int P2 { get; set; }
|
||
}
|
||
|
||
public static class MasterReconnectionPluginExtension
|
||
{
|
||
public static ReconnectionPlugin<IModbusTcpMaster> UseModbusTcpMasterReconnectionPlugin(this IPluginManager pluginManager)
|
||
{
|
||
ModbusTcpMasterReconnectionPlugin modbusTcpMasterReconnectionPlugin = new ModbusTcpMasterReconnectionPlugin();
|
||
pluginManager.Add(modbusTcpMasterReconnectionPlugin);
|
||
return modbusTcpMasterReconnectionPlugin;
|
||
}
|
||
}
|
||
|
||
internal sealed class ModbusTcpMasterReconnectionPlugin : ReconnectionPlugin<IModbusTcpMaster>, ITcpClosedPlugin
|
||
{
|
||
public override Func<IModbusTcpMaster, int, Task<bool?>> ActionForCheck { get; set; }
|
||
|
||
public ModbusTcpMasterReconnectionPlugin()
|
||
{
|
||
this.ActionForCheck = (c, i) => Task.FromResult<bool?>(c.Online);
|
||
}
|
||
|
||
public async Task OnTcpClosed(ITcpSession client, ClosedEventArgs e)
|
||
{
|
||
await e.InvokeNext().ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||
|
||
if (client is not IModbusTcpMaster tClient)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (e.Manual)
|
||
{
|
||
return;
|
||
}
|
||
|
||
_ = Task.Run(async () =>
|
||
{
|
||
while (true)
|
||
{
|
||
if (this.DisposedValue)
|
||
{
|
||
return;
|
||
}
|
||
if (await this.ActionForConnect.Invoke(tClient).ConfigureAwait(EasyTask.ContinueOnCapturedContext))
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
});
|
||
}
|
||
} |