using HslCommunication; using HslCommunication.Core; using HslCommunication.ModBus; using HybirdFrameworkCore.Utils; using log4net; namespace HybirdFrameworkDriver.ModbusTcpMaster; public class ModbusTcpMaster { public delegate void MyReadAction(ModbusTcpMaster str); private static readonly ILog Log = LogManager.GetLogger(typeof(ModbusTcpMaster)); private ModbusTcpNet ModbusTcpNet; public string Ip { get; set; } = "127.0.0.1"; public int Port { get; set; } = 502; public static DataFormat DataFormat { get; set; } = DataFormat.ABCD; public int Duration { get; set; } = 1000; public bool Connected { get; set; } public string connectId { get; set; } public MyReadAction? ReadAction { get; set; } private bool StopFlag { get; set; } private ILog GetLog() { return Log; } public bool Connect() { GetLog().Info($"begin to connect {Ip}:{Port}"); try { if (ModbusTcpNet == null) { ModbusTcpNet = new ModbusTcpNet(Ip, Port); ModbusTcpNet.DataFormat = DataFormat; var result = ModbusTcpNet.ConnectServer(); connectId = ModbusTcpNet.ConnectionId; if (result.IsSuccess) { Connected = true; GetLog().Info($"connect {Ip}:{Port} success"); StartListen(); } else { GetLog().Info($"connect {Ip}:{Port} failed {result.Message}"); } } } catch (Exception e) { GetLog().Error($"connect {Ip}:{Port} exception {e.Message}"); } return Connected; } public void StartListen() { StopListen(); StopFlag = false; var readThread = new Thread(ReadFunc) { IsBackground = true, Name = $"{Ip}:{Port}-reader-thread" }; readThread.Start(); } public void StopListen() { StopFlag = true; Thread.Sleep(500); } private void ReadFunc() { if (ReadAction != null) while (!StopFlag) try { ReadAction(this); Thread.Sleep(Duration); } catch (Exception e) { Log.Error(e); } GetLog().Info("stop listen"); } public byte[]? ReadRegister(int registerNo, int start, int length) { start = start % 16 == 0 ? start / 16 : start / 16 + 1; length = length % 8 == 0 ? length / 8 : length / 8 + 1; OperateResult result = ModbusTcpNet.Read("x=3;" + (registerNo + start), (ushort)length); if (result.IsSuccess) return result.Content; return null; } public byte[]? BatchReadHolderRegister(int registerNo, int length) { OperateResult result = ModbusTcpNet.Read("x=3;" + registerNo, (ushort)length); if (result.IsSuccess) return result.Content; return null; } public byte[]? BatchReadInputRegister(int registerNo, int length) { OperateResult result = ModbusTcpNet.Read("x=4;" + registerNo, (ushort)length); if (result.IsSuccess) return result.Content; return null; } /// /// 读取线圈,需要指定起始地址,如果富文本地址不指定,默认使用的功能码是 0x01
/// To read the coil, you need to specify the start address. If the rich text address is not specified, the default function code is 0x01. ///
/// 起始地址,格式为"1234" /// 带有成功标志的bool对象 public OperateResult ReadCoil(string address) => ModbusTcpNet.ReadBool(address); /// /// 批量的读取线圈,需要指定起始地址,读取长度,如果富文本地址不指定,默认使用的功能码是 0x01
/// For batch reading coils, you need to specify the start address and read length. If the rich text address is not specified, the default function code is 0x01. ///
/// 起始地址,格式为"1234" /// 读取长度 /// 带有成功标志的bool数组对象 public OperateResult ReadCoil(string address, ushort length) { return ModbusTcpNet.ReadBool(address, length); } /// /// 读取输入线圈,需要指定起始地址,如果富文本地址不指定,默认使用的功能码是 0x02
/// To read the input coil, you need to specify the start address. If the rich text address is not specified, the default function code is 0x02. ///
/// 起始地址,格式为"1234" /// 带有成功标志的bool对象 public OperateResult ReadDiscrete(string address) { return ModbusTcpNet.ReadDiscrete(address); } /// /// 批量的读取输入点,需要指定起始地址,读取长度,如果富文本地址不指定,默认使用的功能码是 0x02
/// To read input points in batches, you need to specify the start address and read length. If the rich text address is not specified, the default function code is 0x02 ///
/// 起始地址,格式为"1234" /// 读取长度 /// 带有成功标志的bool数组对象 public OperateResult ReadDiscrete(string address, ushort length) { return ModbusTcpNet.ReadDiscrete(address, length); } public bool WriteValue(ModbusProperty property) { var value = property.Value; if (value == null) { GetLog().Warn($"write property{property.RegisterNo} null value"); return false; } var result = false; var dataType = property.Type; var start = property.Start; var length = property.Length; var registerNo = property.RegisterNo - 40000; var setValue = BitUtls.Value2Bytes(value, property.Scale, property.Offset); OperateResult operateResult; switch (dataType) { case ModbusDataType.Register: if (setValue.Length < length * 2) { //byte 需要读取寄存器中的内容 if (typeof(T) == typeof(byte)) { OperateResult readResultRegister = ModbusTcpNet.Read("x=3;" + registerNo, 1); if (readResultRegister.IsSuccess) { switch (DataFormat) { case DataFormat.ABCD: readResultRegister.Content[1] = setValue[0]; break; case DataFormat.BADC: readResultRegister.Content[0] = setValue[0]; break; } operateResult = ModbusTcpNet.Write("x=16;" + registerNo, readResultRegister.Content); result = operateResult.IsSuccess; } } //其他类型 String 占用几个寄存器 直接补0 else { var preWriteCont = new byte[length * 2]; switch (DataFormat) { case DataFormat.ABCD: for (var i = 0; i < setValue.Length; i++) if (i % 2 == 0) preWriteCont[i + 1] = setValue[i]; else preWriteCont[i - 1] = setValue[i]; break; case DataFormat.BADC: Array.Copy(setValue, preWriteCont, setValue.Length); break; } operateResult = ModbusTcpNet.Write("x=16;" + registerNo, preWriteCont); result = operateResult.IsSuccess; } } else if (setValue.Length == length * 2) { var preWriteCont = new byte[setValue.Length]; switch (DataFormat) { case DataFormat.ABCD: for (var i = 0; i < setValue.Length; i++) if (i % 2 == 0) preWriteCont[i + 1] = setValue[i]; else preWriteCont[i - 1] = setValue[i]; break; case DataFormat.BADC: //Array.Copy(setValue, preWriteCont, setValue.Length); break; } operateResult = ModbusTcpNet.Write("x=16;" + registerNo, preWriteCont); result = operateResult.IsSuccess; } break; case ModbusDataType.Bit: result = WriteRegisterOneBit(registerNo, start, Convert.ToBoolean(value)); break; } return result; } /// /// 写寄存器中的一个bit /// /// /// /// /// public bool WriteRegisterOneBit(int addr, int location, bool boolResult) { if (!Connected) return false; var result = false; ushort registerValue1 = 0x1234; ushort mask = 0x1234; OperateResult readResult = ModbusTcpNet.Read("x=3;" + addr, 1); if (readResult.IsSuccess) if (location >= 0 && location <= 15) { registerValue1 = ModbusTcpNet.ByteTransform.TransUInt16(readResult.Content, 0); if (boolResult) { mask = (ushort)(1 << location); registerValue1 |= mask; } else { mask = (ushort)~(1 << location); registerValue1 &= mask; } var writeResult = ModbusTcpNet.Write("x=6;" + addr, registerValue1); if (writeResult.IsSuccess) result = true; } return result; } }