整体思路
读写抽象类
using System;
using System.Collections.Concurrent;
using System.IO.Ports;
using System.Net;
using System.Net.Sockets;
using Modbus.Device;
using ModbusHandler.ModbusTypes;
namespace ModbusHandler
{
public abstract class ModbusCommTypeAbstract<T> : IModbusCommType<T>
{
public abstract T Read(request req);
public abstract void Write(writerequest<T> wreq);
/// <summary>
/// 通讯连接池
/// </summary>
ConcurrentDictionary<string, IModbusMaster> connections = new ConcurrentDictionary<string, IModbusMaster>();
/// <summary>
/// 连接信息
/// </summary>
public virtual void ConnInfo()
{
foreach (var conn in connections)
{
Console.WriteLine($"IP连接字符串:{ conn.Key } Modbus主设备:{conn.Value}");
}
}
/// <summary>
/// 验证IP连接字符串
/// </summary>
/// <param name="conn">IP连接字符串</param>
/// <param name="ip"></param>
/// <param name="port"></param>
/// <returns>正确IP和端口,返回true</returns>
private bool verifyIPConnectionString(string conn, out IPAddress ip, out int port)
{
port = 0;
ip = null;
var connectionarray = conn.Split(':');
return connectionarray.Length == 2 && int.TryParse(connectionarray[1], out port) &&
IPAddress.TryParse(connectionarray[0], out ip);
}
/// <summary>
/// 获取或添加连接
/// </summary>
/// <param name="ctype">连接类型(网络/串口)</param>
/// <param name="conn">IP连接字符串</param>
/// <returns>Modbus主设备</returns>
protected IModbusMaster GetOrAddConnection(ConnectionType ctype, string conn)
{
switch (ctype)
{
case ConnectionType.SERIALRTU:
return connections.GetOrAdd(conn, (arg) => ModbusSerialMaster.CreateRtu(new SerialPort(conn)));
case ConnectionType.SERIALASCII:
return connections.GetOrAdd(conn, (arg) => ModbusSerialMaster.CreateAscii(new SerialPort(conn)));
case ConnectionType.TCP:
return !verifyIPConnectionString(conn, out var ip, out var port)
? null
: connections.GetOrAdd(conn,
(arg) => ModbusIpMaster.CreateIp(new TcpClient(ip.ToString(), port)));
}
return null;
}
}
}
实现Holding读写类如下;
其他三个类代码类似.
InputRegisters;
Inputs
Coils
namespace ModbusHandler
{
public sealed class HoldingRegisters : ModbusCommTypeAbstract<ushort[]>
{
/// <inheritdoc />
static HoldingRegisters() { }
private HoldingRegisters() { }
public static HoldingRegisters Instance { get; } = new HoldingRegisters();
public override ushort[] Read(request req)
{
return GetOrAddConnection(req.connectiontype, req.destination)?.ReadHoldingRegisters(req.slaveid, req.address, req.count);
}
public override void Write(writerequest<ushort[]> wreq)
{
GetOrAddConnection(wreq.connectiontype,wreq.destination)?.WriteMultipleRegisters(wreq.slaveid, wreq.address, wreq.data);
}
}
}
通讯请求models如下:
namespace ModbusHandler
{
//{
//"destination": "127.0.0.1:502",
//"connectiontype": 2,
//"slaveid": 1,
//"address": 0,
//"count": 5
//}
/// <summary>
/// 请求格式
/// </summary>
public class request
{
public string destination { get; set; }
public ConnectionType connectiontype { get; set;}
public byte slaveid { get; set; }
public ushort address { get; set; }
public ushort count { get; set; }
public override string ToString() => "目标:" + this.destination + " 从站:" + this.slaveid + " 起始地址:" + this.address +
" 数量:" + this.count;
}
/// <summary>
/// 写入请求格式
/// </summary>
/// <typeparam name="T"></typeparam>
public class writerequest<T> : request
{
//{
//"destination": "127.0.0.1:502",
//"connectiontype": 2,
//"slaveid": 1,
//"address": 0,
//"data": [1,2,5]
//}
public T data { get; set; }
public override string ToString() => "目标:" + this.destination + " 从站:" + this.slaveid + " 起始地址:" +
this.address + " 数据:" + this.data;
}
}
至此,Nmodbus4<2.1.0>封装完成.可以直接调用自己的DLL来使用了.
今天也测试了一下NModbus4 3.0.0-alpha2
发现不支持串口模式了.串口被淘汰也是大势所趋.
经过测试也还比较稳定.