From e79700d34620c495667b7b8e7b852f23ed7d7e4e Mon Sep 17 00:00:00 2001 From: kazelee <1847801760@qq.com> Date: 星期三, 16 七月 2025 17:30:42 +0800 Subject: [PATCH] 简化增删改表达式,避免类型匹配出错 --- device/ModbusFactory.cs | 516 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 459 insertions(+), 57 deletions(-) diff --git a/device/ModbusFactory.cs b/device/ModbusFactory.cs index 28578f8..83a15ae 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閫氳鎺ュ彛 @@ -48,13 +49,31 @@ /// <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); } @@ -80,7 +99,15 @@ } 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); + } } } @@ -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($"璇诲彇鎴愬姛锛歊eadCoils:IP:{ip},Port:{port}"); } else { //璇诲彇澶辫触 - LogHelper.Info($"璇诲彇澶辫触锛歊eadCoils"); + LogHelper.Info($"璇诲彇澶辫触锛歊eadCoils: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($"璇诲彇鎴愬姛锛歊eadDiscreteInputs:IP:{ip},Port:{port}"); } else { //璇诲彇澶辫触 - LogHelper.Info($"璇诲彇澶辫触锛歊eadDiscreteInputs"); + LogHelper.Info($"璇诲彇澶辫触锛歊eadDiscreteInputs: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绫诲瀷 res = client.ReadHoldingRegisters(startingAddress, quantity); if (res.Length != 0) { //璇诲彇鎴愬姛 + LogHelper.Info($"璇诲彇鎴愬姛锛歊eadHoldingRegisters:IP:{ip},Port:{port}"); } else { //璇诲彇澶辫触 + LogHelper.Info($"璇诲彇澶辫触锛歊eadHoldingRegisters: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($"璇诲彇鎴愬姛锛歊eadInputRegisters:IP:{ip},Port:{port}"); } else { //璇诲彇澶辫触 + LogHelper.Info($"璇诲彇澶辫触锛歊eadInputRegisters: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($"鍐欏叆鎴愬姛锛歐riteSingleCoil:IP:{ip},Port:{port}"); } else { //鍐欏叆澶辫触 + LogHelper.Info($"鍐欏叆澶辫触锛歐riteSingleCoil: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($"鍐欏叆鎴愬姛锛歐riteSingleRegister:IP:{ip},Port:{port}"); } else { //鍐欏叆澶辫触 + LogHelper.Info($"鍐欏叆澶辫触锛歐riteSingleRegister: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($"鍐欏叆鎴愬姛锛歐riteMultipleCoils:IP:{ip},Port:{port}"); } else { //鍐欏叆澶辫触 + LogHelper.Info($"鍐欏叆澶辫触锛歐riteMultipleCoils: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"); + + // 鏋勫缓璇锋眰鎶ユ枃锛�2瀛楄妭锛�+ 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銆佸崗璁甀D銆佸崟鍏冩爣璇嗙 + 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鍑犱箮鐩稿悓锛屼粎鍔熻兘鐮佹敼涓�x02 + 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"); + + // 鏋勫缓璇锋眰鎶ユ枃锛�2瀛楄妭锛�+ 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銆佸崗璁甀D銆佸崟鍏冩爣璇嗙 + 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; + + // 闀垮害瀛楁锛堝悗闈㈣繕鏈�瀛楄妭锛�+ 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); + + // 妫�煡鍥炴樉鍝嶅簲锛堝悓WriteSingleCoil锛�+ 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"); + + // 璁$畻闇�鐨勫瓧鑺傛暟锛堟瘡涓瓧鑺傚瓨鍌�涓嚎鍦堢姸鎬侊級 + 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); + } + } + + // 鏋勫缓璇锋眰鎶ユ枃锛�3 + 绾垮湀瀛楄妭鏁帮級 + 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); + + // 璇诲彇鍝嶅簲锛堝浐瀹�2瀛楄妭锛�+ 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]; + } + + // 鏋勫缓璇锋眰鎶ユ枃锛�3 + 鍊煎瓧鑺傛暟锛�+ 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); + + // 璇诲彇鍝嶅簲锛堝浐瀹�2瀛楄妭锛�+ 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