From f8d23dcf8d6501482db1a5180325194232afe96c Mon Sep 17 00:00:00 2001 From: kazelee <1847801760@qq.com> Date: 星期五, 18 七月 2025 17:30:09 +0800 Subject: [PATCH] 封装部分业务代码,继续优化日志打印流程 --- device/ModbusFactory.cs | 540 ++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 471 insertions(+), 69 deletions(-) diff --git a/device/ModbusFactory.cs b/device/ModbusFactory.cs index 28578f8..4c84a8a 100644 --- a/device/ModbusFactory.cs +++ b/device/ModbusFactory.cs @@ -8,6 +8,7 @@ using System.Linq; using TcpClient = System.Net.Sockets.TcpClient; +using System.IO; namespace HH.WCS.Mobox3.DSZSH.device { // 瀹氫箟Modbus閫氳鎺ュ彛 @@ -20,41 +21,59 @@ // 甯哥敤鐨凪odbus鍔熻兘鐮佹柟娉� /// <summary> - /// 璇讳竴涓垨澶氫釜绾垮湀锛岃繑鍥炰竴涓猙it鐪熷亣鏁扮粍 + /// 璇讳竴涓垨澶氫釜绾垮湀,杩斿洖涓�釜bit鐪熷亣鏁扮粍 /// </summary> /// <param name="startingAddress"></param> /// <param name="quantity"></param> /// <returns></returns> bool[] ReadCoils(int startingAddress, int quantity); /// <summary> - /// 璇讳竴涓垨澶氫釜绂绘暎杈撳叆锛岃繑鍥炰竴涓猙it鐪熷亣鏁扮粍 + /// 璇讳竴涓垨澶氫釜绂绘暎杈撳叆,杩斿洖涓�釜bit鐪熷亣鏁扮粍 /// </summary> /// <param name="startingAddress"></param> /// <param name="quantity"></param> /// <returns></returns> bool[] ReadDiscreteInputs(int startingAddress, int quantity); /// <summary> - /// 鎵归噺璇诲彇鎴栧崟鐙鍙栦繚鎸佸瘎瀛樺櫒锛岃繑鍥炵殑鏄�2浣峣nt鏁扮粍 + /// 鎵归噺璇诲彇鎴栧崟鐙鍙栦繚鎸佸瘎瀛樺櫒,杩斿洖鐨勬槸32浣峣nt鏁扮粍 /// </summary> /// <param name="startingAddress"></param> /// <param name="quantity"></param> /// <returns></returns> int[] ReadHoldingRegisters(int startingAddress, int quantity); /// <summary> - /// 璇讳竴涓垨澶氫釜杈撳叆瀵勫瓨鍣紝杩斿洖涓�釜int32浣嶆暟缁�+ /// 璇讳竴涓垨澶氫釜杈撳叆瀵勫瓨鍣�杩斿洖涓�釜int32浣嶆暟缁� /// </summary> /// <param name="startingAddress"></param> /// <param name="quantity"></param> /// <returns></returns> int[] ReadInputRegisters(int startingAddress, int quantity); /// <summary> - /// + /// 鍐欏叆鍗曚釜绾垮湀 /// </summary> /// <param name="coilAddress"></param> /// <param name="value"></param> bool WriteSingleCoil(int coilAddress, bool value); + /// <summary> + /// 鍐欏叆鍗曚釜瀵勫瓨鍣ㄦ暟鎹�+ /// </summary> + /// <param name="registerAddress"></param> + /// <param name="value"></param> + /// <returns></returns> bool WriteSingleRegister(int registerAddress, ushort value); + /// <summary> + /// 鍐欏叆澶氫釜绾垮湀 + /// </summary> + /// <param name="startingAddress"></param> + /// <param name="values"></param> + /// <returns></returns> bool WriteMultipleCoils(int startingAddress, bool[] values); + /// <summary> + /// 鍐欏叆澶氫釜瀵勫瓨鍣ㄦ暟鎹�+ /// </summary> + /// <param name="startingAddress"></param> + /// <param name="values"></param> + /// <returns></returns> bool WriteMultipleRegisters(int startingAddress, int[] values); } @@ -73,14 +92,22 @@ case ModbusCommunicationType.TcpSocket: return new TcpSocketCommunicator(); default: - //throw new ArgumentException("涓嶆敮鎸佺殑Modbus閫氫俊鏂瑰紡锛氳閫夋嫨EasyModbus鎴朤cpSocket"); - LogHelper.Info("涓嶆敮鎸佺殑Modbus閫氫俊鏂瑰紡锛氳閫夋嫨EasyModbus鎴朤cpSocket"); + //throw new ArgumentException("涓嶆敮鎸佺殑Modbus閫氫俊鏂瑰紡:璇烽�鎷〦asyModbus鎴朤cpSocket"); + LogHelper.Info("涓嶆敮鎸佺殑Modbus閫氫俊鏂瑰紡:璇烽�鎷〦asyModbus鎴朤cpSocket"); return null; } } static void Test() { - var communicator = ModbusFactory.CreateCommunicator(ModbusCommunicationType.TcpSocket); + try { + var communicator = ModbusFactory.CreateCommunicator(ModbusCommunicationType.TcpSocket); + + communicator.Link("127.0.0.1", 502); + var read = communicator.ReadInputRegisters(0, 5); + } + catch (Exception ex) { + LogHelper.InfoEx(ex); + } } } @@ -100,10 +127,10 @@ _modbusClient.Connect(); if (IsConnected) { - LogHelper.Info($"杩炴帴鎴愬姛锛歿ipAddress}:{port}"); + LogHelper.Info($"杩炴帴鎴愬姛:{ipAddress}:{port}"); } else { - LogHelper.Info($"杩炴帴澶辫触锛歿ipAddress}:{port}"); + LogHelper.Info($"杩炴帴澶辫触:{ipAddress}:{port}"); } } @@ -116,10 +143,10 @@ _modbusClient?.Disconnect(); if (IsConnected) { - LogHelper.Info($"杩炴帴鎴愬姛锛歿_modbusClient.IPAddress}:{_modbusClient.Port}"); + LogHelper.Info($"杩炴帴鎴愬姛:{_modbusClient.IPAddress}:{_modbusClient.Port}"); } else { - LogHelper.Info($"杩炴帴澶辫触锛歿_modbusClient.IPAddress} : {_modbusClient.Port}"); + LogHelper.Info($"杩炴帴澶辫触:{_modbusClient.IPAddress} : {_modbusClient.Port}"); } } @@ -134,16 +161,19 @@ public bool[] ReadCoils(int startingAddress, int quantity) { bool[] res = new bool[0]; + var client = _modbusClient; if (_modbusClient != null && IsConnected) { + var ip = client.IPAddress; + var port = client.Port; try { res = _modbusClient.ReadCoils(startingAddress, quantity); if (res.Length != 0) { //璇诲彇鎴愬姛 - LogHelper.Info($"璇诲彇鎴愬姛锛歊eadCoils"); + LogHelper.Info($"璇诲彇鎴愬姛:ReadCoils:IP:{ip},Port:{port}"); } else { //璇诲彇澶辫触 - LogHelper.Info($"璇诲彇澶辫触锛歊eadCoils"); + LogHelper.Info($"璇诲彇澶辫触:ReadCoils:IP:{ip},Port:{port}"); } } catch (Exception ex) { @@ -151,23 +181,26 @@ } } else { - LogHelper.Info($"璁惧鏈繛鎺ワ紝璇诲彇澶辫触锛歊eadCoils"); + LogHelper.Info($"鏈壘鍒癕odbus璁惧瀹炰緥瀵硅薄,鎴栧璞℃湭鎴愬姛杩炴帴"); } return res; } public bool[] ReadDiscreteInputs(int startingAddress, int quantity) { bool[] res = new bool[0]; + var client = _modbusClient; if (_modbusClient != null && IsConnected) { + var ip = client.IPAddress; + var port = client.Port; try { res = _modbusClient.ReadDiscreteInputs(startingAddress, quantity); if (res.Length != 0) { //璇诲彇鎴愬姛 - LogHelper.Info($"璇诲彇鎴愬姛锛歊eadDiscreteInputs"); + LogHelper.Info($"璇诲彇鎴愬姛:ReadDiscreteInputs:IP:{ip},Port:{port}"); } else { //璇诲彇澶辫触 - LogHelper.Info($"璇诲彇澶辫触锛歊eadDiscreteInputs"); + LogHelper.Info($"璇诲彇澶辫触:ReadDiscreteInputs:IP:{ip},Port:{port}"); } } catch (Exception ex) { @@ -175,7 +208,7 @@ } } else { - LogHelper.Info($"璁惧鏈繛鎺ワ紝璇诲彇澶辫触锛歊eadDiscreteInputs"); + LogHelper.Info($"鏈壘鍒癕odbus璁惧瀹炰緥瀵硅薄,鎴栧璞℃湭鎴愬姛杩炴帴"); } return res; } @@ -183,26 +216,28 @@ public int[] ReadHoldingRegisters(int startingAddress, int quantity) { int[] res = new int[0]; var client = _modbusClient; - var ip = client.IPAddress; - var port = client.Port; if (client != null && client.Connected) { + var ip = client.IPAddress; + var port = client.Port; try { - //涓�釜瀵勫瓨鍣ㄦ槸16浣嶏紝杩斿洖2涓猧nt绫诲瀷 + //涓�釜瀵勫瓨鍣ㄦ槸16浣�杩斿洖2涓猧nt绫诲瀷 res = client.ReadHoldingRegisters(startingAddress, quantity); if (res.Length != 0) { //璇诲彇鎴愬姛 + LogHelper.Info($"璇诲彇鎴愬姛:ReadHoldingRegisters:IP:{ip},Port:{port}"); } else { //璇诲彇澶辫触 + LogHelper.Info($"璇诲彇澶辫触:ReadHoldingRegisters:IP:{ip},Port:{port}"); } } catch (Exception ex) { - //濡傛灉璇锋眰鏁伴噺瓒呭嚭淇濇寔瀵勫瓨鍣ㄧ殑鏈�ぇ鏁版嵁琛屾暟锛屼細鎶ラ敊 - LogHelper.Info($"鍙戠敓浜嗗紓甯�{ex.Message},IP:{ip},Port:{port}", "Error"); + //濡傛灉璇锋眰鏁伴噺瓒呭嚭淇濇寔瀵勫瓨鍣ㄧ殑鏈�ぇ鏁版嵁琛屾暟,浼氭姤閿�+ LogHelper.InfoEx(ex); } } else { - LogHelper.Info($"鏈壘鍒癕odbus璁惧瀹炰緥瀵硅薄:IP:{ip},Port:{port}"); + LogHelper.Info($"鏈壘鍒癕odbus璁惧瀹炰緥瀵硅薄,鎴栧璞℃湭鎴愬姛杩炴帴"); } return res; } @@ -210,24 +245,26 @@ public int[] ReadInputRegisters(int startingAddress, int quantity) { int[] res = new int[0]; var client = _modbusClient; - var ip = client.IPAddress; - var port = client.Port; if (client != null && client.Connected) { + var ip = client.IPAddress; + var port = client.Port; try { res = client.ReadInputRegisters(startingAddress, quantity); if (res.Length != 0) { //璇诲彇鎴愬姛 + LogHelper.Info($"璇诲彇鎴愬姛:ReadInputRegisters:IP:{ip},Port:{port}"); } else { //璇诲彇澶辫触 + LogHelper.Info($"璇诲彇澶辫触:ReadInputRegisters:IP:{ip},Port:{port}"); } } catch (Exception ex) { - + LogHelper.InfoEx(ex); } } else { - + LogHelper.Info($"鏈壘鍒癕odbus璁惧瀹炰緥瀵硅薄,鎴栧璞℃湭鎴愬姛杩炴帴"); } return res; } @@ -235,25 +272,27 @@ public bool WriteSingleCoil(int coilAddress, bool value) { var res = false; var client = _modbusClient; - var ip = client.IPAddress; - var port = client.Port; if (client != null && client.Connected) { + var ip = client.IPAddress; + var port = client.Port; try { client.WriteSingleCoil(coilAddress, value); res = value == client.ReadCoils(coilAddress, 1)[0]; if (res) { //鍐欏叆鎴愬姛 + LogHelper.Info($"鍐欏叆鎴愬姛:WriteSingleCoil:IP:{ip},Port:{port}"); } else { //鍐欏叆澶辫触 + LogHelper.Info($"鍐欏叆澶辫触:WriteSingleCoil:IP:{ip},Port:{port}"); } } catch (Exception ex) { - + LogHelper.InfoEx(ex); } } else { - + LogHelper.Info($"鏈壘鍒癕odbus璁惧瀹炰緥瀵硅薄,鎴栧璞℃湭鎴愬姛杩炴帴"); } return res; } @@ -261,25 +300,27 @@ public bool WriteSingleRegister(int registerAddress, ushort value) { var res = false; var client = _modbusClient; - var ip = client.IPAddress; - var port = client.Port; if (client != null && client.Connected) { + var ip = client.IPAddress; + var port = client.Port; try { client.WriteSingleRegister(registerAddress, value); res = value == client.ReadHoldingRegisters(registerAddress, 1)[0]; if (res) { //鍐欏叆鎴愬姛 + LogHelper.Info($"鍐欏叆鎴愬姛:WriteSingleRegister:IP:{ip},Port:{port}"); } else { //鍐欏叆澶辫触 + LogHelper.Info($"鍐欏叆澶辫触:WriteSingleRegister:IP:{ip},Port:{port}"); } } catch (Exception ex) { - + LogHelper.InfoEx(ex); } } else { - + LogHelper.Info($"鏈壘鍒癕odbus璁惧瀹炰緥瀵硅薄,鎴栧璞℃湭鎴愬姛杩炴帴"); } return res; } @@ -287,26 +328,28 @@ public bool WriteMultipleCoils(int startingAddress, bool[] values) { var res = false; var client = _modbusClient; - var ip = client.IPAddress; - var port = client.Port; if (client != null && client.Connected) { + var ip = client.IPAddress; + var port = client.Port; try { client.WriteMultipleCoils(startingAddress, values); var dataRead = client.ReadCoils(startingAddress, values.Length); res = values.SequenceEqual(dataRead); if (res) { //鍐欏叆鎴愬姛 + LogHelper.Info($"鍐欏叆鎴愬姛:WriteMultipleCoils:IP:{ip},Port:{port}"); } else { //鍐欏叆澶辫触 + LogHelper.Info($"鍐欏叆澶辫触:WriteMultipleCoils:IP:{ip},Port:{port}"); } } catch (Exception ex) { - + LogHelper.InfoEx(ex); } } else { - + LogHelper.Info($"鏈壘鍒癕odbus璁惧瀹炰緥瀵硅薄,鎴栧璞℃湭鎴愬姛杩炴帴"); } return res; } @@ -314,33 +357,34 @@ public bool WriteMultipleRegisters(int startingAddress, int[] values) { var res = false; var client = _modbusClient; - var ip = client.IPAddress; - var port = client.Port; - var log = string.Join(",", values.Select(x => x.ToString())); if (client != null && client.Connected) { + var ip = client.IPAddress; + var port = client.Port; + var log = string.Join(",", values.Select(x => x.ToString())); try { client.WriteMultipleRegisters(startingAddress, values); var dataRead = client.ReadHoldingRegisters(startingAddress, values.Length); res = values.SequenceEqual(dataRead); if (res) { - LogHelper.Info($"鍐欏叆鎴愬姛,IP:{ip},Port:{port},{log}"); + LogHelper.Info($"鍐欏叆鎴愬姛,WriteMultipleRegisters:IP:{ip},Port:{port},{log}"); } else { - LogHelper.Info($"鍐欏叆澶辫触,IP:{ip},Port:{port},{log}"); + LogHelper.Info($"鍐欏叆澶辫触,WriteMultipleRegisters:IP:{ip},Port:{port},{log}"); } } catch (Exception ex) { - LogHelper.Info($"鍙戠敓浜嗗紓甯�{ex.Message},IP:{ip},Port:{port},{log}", "Error"); + LogHelper.InfoEx(ex); } } else { - LogHelper.Info($"鏈厤缃殑璁惧淇℃伅,IP:{ip},Port:{port},{log}"); + LogHelper.Info($"鏈壘鍒癕odbus璁惧瀹炰緥瀵硅薄,鎴栧璞℃湭鎴愬姛杩炴帴"); } return res; } public void Dispose() { //_modbusClient?.Dispose(); + GC.SuppressFinalize(_modbusClient); } } @@ -348,9 +392,10 @@ public class TcpSocketCommunicator : IModbusCommunicator { private System.Net.Sockets.TcpClient _tcpClient; private NetworkStream _networkStream; + private byte unitIdentifier = 1; // 榛樿鍗曞厓鏍囪瘑绗� - //public bool IsConnected => _tcpClient?.Connected ?? false; - public bool IsConnected { get { if (_tcpClient != null) { return true; } else { return false; } } } + public bool IsConnected => _tcpClient?.Connected ?? false; + //public bool IsConnected { get { if (_tcpClient != null) { return _tcpClient.Connected; } else { return false; } } } public void Link(string ipAddress, int port) { _tcpClient = new System.Net.Sockets.TcpClient(); @@ -372,50 +417,407 @@ } } - // 浠ヤ笅鏂规硶闇�鏍规嵁浣犵殑Modbus TCP鍗忚鍏蜂綋瀹炵幇 public bool[] ReadCoils(int startingAddress, int quantity) { - // 瀹炵幇TCP鏂瑰紡璇诲彇绾垮湀 - throw new NotImplementedException(); + if (quantity < 1 || quantity > 2000) + throw new ArgumentException("Quantity must be between 1 and 2000"); + + // 鏋勫缓璇锋眰鎶ユ枃 (12瀛楄妭) + byte[] request = new byte[12]; + request[0] = 0x00; // 浜嬪姟ID楂樺瓧鑺�+ request[1] = 0x01; // 浜嬪姟ID浣庡瓧鑺�(绀轰緥鍊� + request[2] = 0x00; // 鍗忚ID楂樺瓧鑺�(鍥哄畾0) + request[3] = 0x00; // 鍗忚ID浣庡瓧鑺�(鍥哄畾0) + request[4] = 0x00; // 闀垮害楂樺瓧鑺�(鍚庣画6瀛楄妭) + request[5] = 0x06; // 闀垮害浣庡瓧鑺�+ request[6] = unitIdentifier; // 鍗曞厓鏍囪瘑绗�+ request[7] = 0x01; // 鍔熻兘鐮�(璇荤嚎鍦� + request[8] = (byte)(startingAddress >> 8); // 璧峰鍦板潃楂樺瓧鑺�+ request[9] = (byte)startingAddress; // 璧峰鍦板潃浣庡瓧鑺�+ request[10] = (byte)(quantity >> 8); // 鏁伴噺楂樺瓧鑺�+ request[11] = (byte)quantity; // 鏁伴噺浣庡瓧鑺�+ + // 鍙戦�璇锋眰 + _networkStream.Write(request, 0, request.Length); + + // 璇诲彇鍝嶅簲澶�(8瀛楄妭) + byte[] responseHeader = new byte[8]; + int bytesRead = _networkStream.Read(responseHeader, 0, 8); + if (bytesRead != 8) + throw new Exception("Invalid response header length"); + + // 鏍¢獙浜嬪姟ID,鍗忚ID,鍗曞厓鏍囪瘑绗�+ if (responseHeader[0] != request[0] || responseHeader[1] != request[1] || + responseHeader[2] != 0x00 || responseHeader[3] != 0x00 || + responseHeader[6] != unitIdentifier) + throw new Exception("Invalid response header"); + + // 妫�煡寮傚父鍝嶅簲 (鍔熻兘鐮�+ 0x80) + if (responseHeader[7] == 0x81) { + int errorCode = _networkStream.ReadByte(); + throw new Exception($"Modbus error. Code: {errorCode}"); + } + else if (responseHeader[7] != 0x01) + throw new Exception("Invalid function code in response"); + + // 璇诲彇鏁版嵁閮ㄥ垎 (瀛楄妭鏁�+ 瀹為檯鏁版嵁) + byte byteCount = responseHeader[8]; + byte[] responseData = new byte[byteCount]; + bytesRead = _networkStream.Read(responseData, 0, byteCount); + if (bytesRead != byteCount) + throw new Exception("Invalid response data length"); + + // 瑙f瀽绾垮湀鐘舵� (姣忎釜浣嶈〃绀轰竴涓嚎鍦� + bool[] coils = new bool[quantity]; + for (int i = 0; i < quantity; i++) { + int byteIndex = i / 8; + int bitIndex = i % 8; + coils[i] = (responseData[byteIndex] & (1 << bitIndex)) != 0; + } + + return coils; } public bool[] ReadDiscreteInputs(int startingAddress, int quantity) { - // 瀹炵幇TCP鏂瑰紡璇诲彇绂绘暎杈撳叆 - throw new NotImplementedException(); + // 鎶ユ枃缁撴瀯涓嶳eadCoils鍑犱箮鐩稿悓,浠呭姛鑳界爜鏀逛负0x02 + byte[] request = new byte[12]; + request[0] = 0x00; // 浜嬪姟ID楂樺瓧鑺�+ request[1] = 0x01; // 浜嬪姟ID浣庡瓧鑺�(绀轰緥鍊� + request[2] = 0x00; // 鍗忚ID楂樺瓧鑺�(鍥哄畾0) + request[3] = 0x00; // 鍗忚ID浣庡瓧鑺�(鍥哄畾0) + request[4] = 0x00; // 闀垮害楂樺瓧鑺�(鍚庣画6瀛楄妭) + request[5] = 0x06; // 闀垮害浣庡瓧鑺�+ request[6] = unitIdentifier; + request[7] = 0x02; // 鍔熻兘鐮�璇荤鏁h緭鍏�+ request[8] = (byte)(startingAddress >> 8); // 璧峰鍦板潃楂樺瓧鑺�+ request[9] = (byte)startingAddress; // 璧峰鍦板潃浣庡瓧鑺�+ request[10] = (byte)(quantity >> 8); // 鏁伴噺楂樺瓧鑺�+ request[11] = (byte)quantity; // 鏁伴噺浣庡瓧鑺�+ + _networkStream.Write(request, 0, request.Length); + + // 鍝嶅簲澶勭悊閫昏緫涓嶳eadCoils涓�嚧 + byte[] responseHeader = new byte[8]; + _networkStream.Read(responseHeader, 0, 8); + + // 鏍¢獙鍜屽紓甯稿鐞�(鍙傝�ReadCoils) + if (responseHeader[7] == 0x82) // 寮傚父鍝嶅簲 + { + int errorCode = _networkStream.ReadByte(); + throw new Exception($"Modbus error. Code: {errorCode}"); + } + + byte byteCount = responseHeader[8]; + byte[] responseData = new byte[byteCount]; + _networkStream.Read(responseData, 0, byteCount); + + // 瑙f瀽绂绘暎杈撳叆鐘舵� + bool[] inputs = new bool[quantity]; + for (int i = 0; i < quantity; i++) { + int byteIndex = i / 8; + int bitIndex = i % 8; + inputs[i] = (responseData[byteIndex] & (1 << bitIndex)) != 0; + } + + return inputs; } public int[] ReadHoldingRegisters(int startingAddress, int quantity) { - // 瀹炵幇TCP鏂瑰紡璇诲彇淇濇寔瀵勫瓨鍣�- throw new NotImplementedException(); + if (quantity < 1 || quantity > 125) + throw new ArgumentException("Quantity must be between 1 and 125"); + + // 鏋勫缓璇锋眰鎶ユ枃 (12瀛楄妭) + byte[] request = new byte[12]; + request[0] = 0x00; // 浜嬪姟ID楂樺瓧鑺�(绀轰緥鍊� + request[1] = 0x01; // 浜嬪姟ID浣庡瓧鑺�+ request[2] = 0x00; // 鍗忚ID楂樺瓧鑺�(鍥哄畾0) + request[3] = 0x00; // 鍗忚ID浣庡瓧鑺�(鍥哄畾0) + request[4] = 0x00; // 闀垮害楂樺瓧鑺�(鍚庣画6瀛楄妭) + request[5] = 0x06; // 闀垮害浣庡瓧鑺�+ request[6] = unitIdentifier; // 鍗曞厓鏍囪瘑绗�+ request[7] = 0x03; // 鍔熻兘鐮�(璇讳繚鎸佸瘎瀛樺櫒) + request[8] = (byte)(startingAddress >> 8); // 璧峰鍦板潃楂樺瓧鑺�+ request[9] = (byte)startingAddress; // 璧峰鍦板潃浣庡瓧鑺�+ request[10] = (byte)(quantity >> 8); // 鏁伴噺楂樺瓧鑺�+ request[11] = (byte)quantity; // 鏁伴噺浣庡瓧鑺�+ + // 鍙戦�璇锋眰 + _networkStream.Write(request, 0, request.Length); + + // 璇诲彇鍝嶅簲澶�(8瀛楄妭) + byte[] responseHeader = new byte[8]; + int bytesRead = _networkStream.Read(responseHeader, 0, 8); + if (bytesRead != 8) + throw new Exception("Invalid response header length"); + + // 鏍¢獙浜嬪姟ID,鍗忚ID,鍗曞厓鏍囪瘑绗�+ if (responseHeader[0] != request[0] || responseHeader[1] != request[1] || + responseHeader[2] != 0x00 || responseHeader[3] != 0x00 || + responseHeader[6] != unitIdentifier) + throw new Exception("Invalid response header"); + + // 妫�煡寮傚父鍝嶅簲 (鍔熻兘鐮�+ 0x80) + if (responseHeader[7] == 0x83) { + int errorCode = _networkStream.ReadByte(); + throw new Exception($"Modbus error. Code: {errorCode}"); + } + else if (responseHeader[7] != 0x03) + throw new Exception("Invalid function code in response"); + + // 璇诲彇鏁版嵁閮ㄥ垎 (瀛楄妭鏁�+ 瀹為檯鏁版嵁) + byte byteCount = responseHeader[8]; + byte[] responseData = new byte[byteCount]; + bytesRead = _networkStream.Read(responseData, 0, byteCount); + if (bytesRead != byteCount) + throw new Exception("Invalid response data length"); + + // 瑙f瀽瀵勫瓨鍣ㄥ� (澶х搴� + int[] registers = new int[quantity]; + for (int i = 0; i < quantity; i++) { + int offset = i * 2; + registers[i] = (ushort)((responseData[offset] << 8) | responseData[offset + 1]); + } + + return registers; } public int[] ReadInputRegisters(int startingAddress, int quantity) { - // 瀹炵幇TCP鏂瑰紡璇诲彇杈撳叆瀵勫瓨鍣�- throw new NotImplementedException(); + if (quantity < 1 || quantity > 125) + throw new ArgumentException("Quantity must be between 1 and 125"); + + // 鏋勫缓Modbus TCP璇锋眰鎶ユ枃 + byte[] request = new byte[12]; + + // 浜嬪姟鏍囪瘑绗�(鍙互绠�崟閫掑) + request[0] = 0x00; + request[1] = 0x01; + + // 鍗忚鏍囪瘑绗�(Modbus鍥哄畾涓�) + request[2] = 0x00; + request[3] = 0x00; + + // 闀垮害瀛楁 (鍚庨潰杩樻湁6瀛楄妭) + request[4] = 0x00; + request[5] = 0x06; + + // 鍗曞厓鏍囪瘑绗�+ request[6] = unitIdentifier; + + // 鍔熻兘鐮�(4琛ㄧず璇昏緭鍏ュ瘎瀛樺櫒) + request[7] = 0x04; + + // 璧峰鍦板潃 + request[8] = (byte)(startingAddress >> 8); + request[9] = (byte)startingAddress; + + // 瀵勫瓨鍣ㄦ暟閲�+ request[10] = (byte)(quantity >> 8); + request[11] = (byte)quantity; + + // 鍙戦�璇锋眰 + _networkStream.Write(request, 0, request.Length); + + // 鎺ユ敹鍝嶅簲 + byte[] responseHeader = new byte[8]; + int bytesRead = _networkStream.Read(responseHeader, 0, 8); + + if (bytesRead != 8) + throw new Exception("Invalid response header length"); + + // 妫�煡浜嬪姟ID鍜屽崗璁甀D鏄惁鍖归厤 + if (responseHeader[0] != request[0] || responseHeader[1] != request[1] || + responseHeader[2] != 0x00 || responseHeader[3] != 0x00) + throw new Exception("Invalid response header"); + + // 妫�煡鍗曞厓鏍囪瘑绗﹀拰鍔熻兘鐮�+ if (responseHeader[6] != unitIdentifier) + throw new Exception("Unit identifier mismatch"); + + if (responseHeader[7] != 0x04 && responseHeader[7] != 0x84) + throw new Exception("Invalid function code in response"); + + // 妫�煡寮傚父鍝嶅簲 + if (responseHeader[7] == 0x84) { + byte errorCode = responseHeader[8]; + throw new Exception($"Modbus error response. Error code: {errorCode}"); + } + + // 璇诲彇鍓╀綑鍝嶅簲鏁版嵁 + byte byteCount = responseHeader[8]; + byte[] responseData = new byte[byteCount]; + bytesRead = _networkStream.Read(responseData, 0, byteCount); + + if (bytesRead != byteCount) + throw new Exception("Invalid response data length"); + + // 瑙f瀽瀵勫瓨鍣ㄥ� + int[] registers = new int[quantity]; + for (int i = 0; i < quantity; i++) { + int offset = i * 2; + registers[i] = (ushort)((responseData[offset] << 8) | responseData[offset + 1]); + } + + return registers; } - public bool WriteSingleCoil(int coilAddress, bool value) { - // 瀹炵幇TCP鏂瑰紡鍐欏叆鍗曚釜绾垮湀 - throw new NotImplementedException(); + public bool WriteSingleCoil(int address, bool value) { + // 璇锋眰鎶ユ枃鍥哄畾闀垮害12瀛楄妭 + byte[] request = new byte[12]; + request[0] = 0x00; // 浜嬪姟ID + request[1] = 0x01; + request[2] = 0x00; // 鍗忚ID + request[3] = 0x00; + request[4] = 0x00; // 闀垮害 + request[5] = 0x06; + request[6] = unitIdentifier; + request[7] = 0x05; // 鍔熻兘鐮�+ request[8] = (byte)(address >> 8); // 鍦板潃楂樺瓧鑺�+ request[9] = (byte)address; // 鍦板潃浣庡瓧鑺�+ request[10] = (byte)(value ? 0xFF : 0x00); // ON=0xFF00, OFF=0x0000 + request[11] = 0x00; + + _networkStream.Write(request, 0, request.Length); + + // 鍝嶅簲搴斾笌璇锋眰瀹屽叏涓�嚧 (鍥炴樉) + byte[] response = new byte[12]; + int bytesRead = _networkStream.Read(response, 0, 12); + if (bytesRead != 12) + throw new Exception("Invalid response length"); + + // 鏍¢獙鍥炴樉鎶ユ枃 + for (int i = 0; i < 12; i++) { + if (response[i] != request[i]) + throw new Exception("Response does not match request"); + } + return true; } - public bool WriteSingleRegister(int registerAddress, ushort value) { - // 瀹炵幇TCP鏂瑰紡鍐欏叆鍗曚釜瀵勫瓨鍣�- throw new NotImplementedException(); + public bool WriteSingleRegister(int address, ushort value) { + byte[] request = new byte[12]; + request[0] = 0x00; // 浜嬪姟ID + request[1] = 0x01; + request[2] = 0x00; // 鍗忚ID + request[3] = 0x00; + request[4] = 0x00; // 闀垮害 + request[5] = 0x06; + request[6] = unitIdentifier; + request[7] = 0x06; // 鍔熻兘鐮�+ request[8] = (byte)(address >> 8); // 鍦板潃楂樺瓧鑺�+ request[9] = (byte)address; + request[10] = (byte)(value >> 8); // 鍊奸珮瀛楄妭 + request[11] = (byte)value; // 鍊间綆瀛楄妭 + + _networkStream.Write(request, 0, request.Length); + + // 妫�煡鍥炴樉鍝嶅簲 (鍚學riteSingleCoil) + byte[] response = new byte[12]; + _networkStream.Read(response, 0, 12); + if (!response.SequenceEqual(request)) + throw new Exception("Response mismatch"); + + return true; } public bool WriteMultipleCoils(int startingAddress, bool[] values) { - // 瀹炵幇TCP鏂瑰紡鍐欏叆澶氫釜绾垮湀 - throw new NotImplementedException(); + int quantity = values.Length; + if (quantity < 1 || quantity > 1968) + throw new ArgumentException("Quantity must be between 1 and 1968"); + + // 璁$畻闇�鐨勫瓧鑺傛暟 (姣忎釜瀛楄妭瀛樺偍8涓嚎鍦堢姸鎬� + int byteCount = (quantity + 7) / 8; + byte[] coilBytes = new byte[byteCount]; + + // 灏哹ool鏁扮粍鍘嬬缉涓哄瓧鑺傛暟缁�+ for (int i = 0; i < quantity; i++) { + if (values[i]) { + int byteIndex = i / 8; + int bitIndex = i % 8; + coilBytes[byteIndex] |= (byte)(1 << bitIndex); + } + } + + // 鏋勫缓璇锋眰鎶ユ枃 (13 + 绾垮湀瀛楄妭鏁� + byte[] request = new byte[13 + coilBytes.Length]; + request[0] = 0x00; // 浜嬪姟ID楂樺瓧鑺�+ request[1] = 0x01; // 浜嬪姟ID浣庡瓧鑺�+ request[2] = 0x00; // 鍗忚ID楂樺瓧鑺�+ request[3] = 0x00; // 鍗忚ID浣庡瓧鑺�+ request[4] = (byte)((7 + coilBytes.Length) >> 8); // 闀垮害楂樺瓧鑺�+ request[5] = (byte)(7 + coilBytes.Length); // 闀垮害浣庡瓧鑺�+ request[6] = unitIdentifier; + request[7] = 0x0F; // 鍔熻兘鐮�(鍐欏涓嚎鍦� + request[8] = (byte)(startingAddress >> 8); // 璧峰鍦板潃楂樺瓧鑺�+ request[9] = (byte)startingAddress; // 璧峰鍦板潃浣庡瓧鑺�+ request[10] = (byte)(quantity >> 8); // 鏁伴噺楂樺瓧鑺�+ request[11] = (byte)quantity; // 鏁伴噺浣庡瓧鑺�+ request[12] = (byte)byteCount; // 瀛楄妭鏁�+ Buffer.BlockCopy(coilBytes, 0, request, 13, coilBytes.Length); + + // 鍙戦�璇锋眰 + _networkStream.Write(request, 0, request.Length); + + // 璇诲彇鍝嶅簲 (鍥哄畾12瀛楄妭) + byte[] response = new byte[12]; + int bytesRead = _networkStream.Read(response, 0, 12); + if (bytesRead != 12) + throw new Exception("Invalid response length"); + + // 鏍¢獙鍥炴樉鐨勫湴鍧�拰鏁伴噺 + if (response[8] != request[8] || response[9] != request[9] || + response[10] != request[10] || response[11] != request[11]) + throw new Exception("Response address/quantity mismatch"); + + return true; } public bool WriteMultipleRegisters(int startingAddress, int[] values) { - // 瀹炵幇TCP鏂瑰紡鍐欏叆澶氫釜瀵勫瓨鍣�- throw new NotImplementedException(); + int quantity = values.Length; + if (quantity < 1 || quantity > 123) + throw new ArgumentException("Quantity must be between 1 and 123"); + + // 灏唘short鏁扮粍杞崲涓哄瓧鑺傛暟缁�(澶х搴� + byte[] valueBytes = new byte[quantity * 2]; + for (int i = 0; i < quantity; i++) { + valueBytes[i * 2] = (byte)(values[i] >> 8); + valueBytes[i * 2 + 1] = (byte)values[i]; + } + + // 鏋勫缓璇锋眰鎶ユ枃 (13 + 鍊煎瓧鑺傛暟) + byte[] request = new byte[13 + valueBytes.Length]; + request[0] = 0x00; // 浜嬪姟ID楂樺瓧鑺�+ request[1] = 0x01; // 浜嬪姟ID浣庡瓧鑺�+ request[2] = 0x00; // 鍗忚ID楂樺瓧鑺�+ request[3] = 0x00; // 鍗忚ID浣庡瓧鑺�+ request[4] = (byte)((7 + valueBytes.Length) >> 8); // 闀垮害楂樺瓧鑺�+ request[5] = (byte)(7 + valueBytes.Length); // 闀垮害浣庡瓧鑺�+ request[6] = unitIdentifier; + request[7] = 0x10; // 鍔熻兘鐮�(鍐欏涓瘎瀛樺櫒) + request[8] = (byte)(startingAddress >> 8); // 璧峰鍦板潃楂樺瓧鑺�+ request[9] = (byte)startingAddress; // 璧峰鍦板潃浣庡瓧鑺�+ request[10] = (byte)(quantity >> 8); // 鏁伴噺楂樺瓧鑺�+ request[11] = (byte)quantity; // 鏁伴噺浣庡瓧鑺�+ request[12] = (byte)(quantity * 2); // 瀛楄妭鏁�+ Buffer.BlockCopy(valueBytes, 0, request, 13, valueBytes.Length); + + // 鍙戦�璇锋眰 + _networkStream.Write(request, 0, request.Length); + + // 璇诲彇鍝嶅簲 (鍥哄畾12瀛楄妭) + byte[] response = new byte[12]; + int bytesRead = _networkStream.Read(response, 0, 12); + if (bytesRead != 12) + throw new Exception("Invalid response length"); + + // 鏍¢獙鍥炴樉鐨勫湴鍧�拰鏁伴噺 + if (response[8] != request[8] || response[9] != request[9] || + response[10] != request[10] || response[11] != request[11]) + throw new Exception("Response address/quantity mismatch"); + + return true; } public void Dispose() { _networkStream?.Dispose(); - //_tcpClient?.Dispose(); + _tcpClient?.Dispose(); } } } \ No newline at end of file -- Gitblit v1.9.1