#region ModbusTCP客户端
    public class ModbusTCP : IDisposable
    {
        #region 字段与属性
        private TcpClient tcpClient;  //----------------------------------------TCP 客户端实例
        private NetworkStream stream;  //---------------------------------------网络流,用于收发数据
        private Thread receiveTh;  //-------------------------------------------接收数据线程
        private bool connected = false;  //-------------------------------------当前连接状态
        private readonly object socketLock = new object();  //------------------锁,保证线程安全
        private ManualResetEvent receiveEvent = new ManualResetEvent(false); 
        private byte[] receiveBuffer = new byte[256];  //-----------------------接收缓冲区
        private byte[] responseBytes;  //---------------------------------------存储完整响应报文 
        private byte[] currentResponse;  //-------------------------------------当前接收到的原始数据       
        private static ushort transId = 1;  //----------------------------------Modbus 事务ID,每次递增
        string nameClient;  //--------------------------------------------------客户端名称
        private string currentIp;  //-------------------------------------------当前连接IP
        private int currentPort;  //--------------------------------------------当前连接端口
        private volatile bool disposed = false;  //-----------------------------是否已释放资源
        private readonly object responseLock = new object();  //----------------响应锁
        public del LogInfoDisplay; //-------------------------------------------委托变量-信息显示
        public InfoMsg info = new InfoMsg("", ""); //---------------------------显示信息
        public event Action<string> returnReceiveEvent;//-----------------------数据接收事件
        //自动重连
        private bool autoReconnect = true;  //----------------------------------自动重连,默认开启
        private int reconnectInterval = 5000;  //-------------------------------重连间隔
        private int maxReconnectAttempts = 5;  //-------------------------------重连次数
        public bool AutoReconnect
        {
            get => autoReconnect;
            set { lock (socketLock) autoReconnect = value; }
        }
        public int ReconnectInterval { get; set; } = 3000;  //------------------重连间隔
        public int Timeout { get; set; } = 5000;  //----------------------------超时时间(毫秒)
        public int AddressOffset { get; set; } = 0;  //-------------------------地址偏移,默认M0对应0(如 D100 实际地址为100)
        private static readonly object idLock = new object();
        private static ushort GenerateTransactionId()
        {
            lock (idLock)
            {
                return transId++;
            }
        }
        private System.Timers.Timer heartbeatTimer;  //-------------------------心跳定时器        
        #endregion 
        #region 数据类型枚举
        
        /// <summary>
        /// 读写数据类型
        /// 字 = 16位(short),双字 = 32位(int)
        /// </summary>
        public enum DataType : short
        {
            字 = 1,  
            双字 = 2
        }
        #endregion
        #region 客户端初始化
        /// <summary>
        /// 客户端初始化
        /// </summary>
        /// <param name="name">客户端名称</param>
        /// <param name="receiveData">接收数据事件</param>
        /// <param name="info">消息显示事件</param>
        /// <param name="addressOffset">地址偏移量(如M0对应0,则为0;若PLC从1开始则设为-1)</param> 
        public void Initialize(string name = "客户端", Action<string> receiveData = null, del info = null, int addressOffset = 0)
        {
            nameClient = name;  //-----------------------客户端名称
            returnReceiveEvent += receiveData;  //-------接收数据事件
            LogInfoDisplay += info;  //------------------消息事件
            this.info.msgType = nameClient;  //----------log消息类型
            this.AddressOffset = addressOffset;  //------地址偏移设置
        }
        /// <summary>
        /// 配置自动重连
        /// </summary>
        /// <param name="enabled">开启重连true/false</param>
        /// <param name="intervalMs">重连间隔</param>
        /// <param name="maxAttempts">重连次数</param>
        public void ConfigureAutoReconnect(bool enabled, int intervalMs = 5000, int maxAttempts = 5)
        {
            autoReconnect = enabled;
            reconnectInterval = intervalMs;
            maxReconnectAttempts = maxAttempts;
            AutoReconnect = autoReconnect;
            ReconnectInterval = reconnectInterval;
        }
        /// <summary>
        /// 配置并启用心跳功能
        /// 通过定时器周期性向指定地址写入0/1交替信号,用于PLC监控连接状态
        /// </summary>
        /// <param name="enabled">是否启用心跳功能,true=启用,false=禁用</param>
        /// <param name="address">心跳信号写入的PLC地址,如"D750"</param>
        /// <param name="intervalMs">心跳间隔时间,单位毫秒,默认500ms</param>
        /// <example>
        /// // 启用心跳,每500ms向D750地址写入0/1交替信号
        /// modbusTCP.ConfigureHeartbeat(true, "D750", 500);
        /// 
        /// // 禁用心跳功能
        /// modbusTCP.ConfigureHeartbeat(false);
        /// </example>
        public void ConfigureHeartbeat(bool enabled = true, string address = "D700", int intervalMs = 500)
        {
            // 停止并释放之前的心跳定时器,避免多个定时器同时运行
            heartbeatTimer?.Stop();      // 停止定时器
            heartbeatTimer?.Dispose();   // 释放定时器资源
            heartbeatTimer = null;
            // 如果禁用心跳,直接返回
            if (!enabled) return;
            // 创建新的心跳定时器
            heartbeatTimer = new System.Timers.Timer(intervalMs);
            bool state = false;  // 心跳状态标志,用于0/1交替
            heartbeatTimer.Elapsed += async (s, e) =>
            {
                try
                {
                    if (!connected) return;
                    state = !state;
                    await WriteSingleRegistersAsync(1, address, state ? 1 : 0);
                }
                catch (Exception ex)
                {
                    // 异常必须在 async void 中捕获,否则会崩溃整个程序
                    Console.WriteLine("[Heartbeat] Exception: " + ex.Message);
                }
                
            };
            heartbeatTimer.Start();
        }
        #endregion
        #region 连接与断开
        /// <summary>
        /// 连接到 Modbus TCP 服务器
        /// </summary>
        /// <param name="ip">PLC IP 地址</param>
        /// <param name="port">端口,默认 502</param>
        /// <returns>是否连接成功</returns>
        public bool Connect(string ip, int port = 502)
        {
            lock (socketLock)
            {
                if (connected) return true; // 已连接则直接返回
                try
                {
                    tcpClient = new TcpClient();
                    tcpClient.SendTimeout = Timeout;
                    tcpClient.ReceiveTimeout = Timeout;
                    var result = tcpClient.BeginConnect(IPAddress.Parse(ip), port, null, null);
                    var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromMilliseconds(Timeout));
                    if (!success)
                    {
                        info.msg = $"连接超时 ({ip}:{port})";
                        LogInfoDisplay?.Invoke(info);
                        return false;
                    }
                    tcpClient.EndConnect(result);
                    stream = tcpClient.GetStream();
                    connected = true;
                    currentIp = ip;
                    currentPort = port;
                    StartReceiveThread(); // 启动接收线程
                    info.msg = $"连接成功 {ip}:{port}";
                    LogInfoDisplay?.Invoke(info);
                    return true;
                }
                catch (Exception ex)
                {
                    info.msg = $"连接失败: {ex.Message}";
                    LogInfoDisplay?.Invoke(info);
                    Disconnect();
                    HandleReconnection();
                    return false;
                }
            }
        }
        /// <summary>
        /// 断开连接
        /// </summary>
        public void Disconnect()
        {
            lock (socketLock)
            {
                if (!connected) return;
                try
                {
                    connected = false;
                    receiveEvent.Set();
                    receiveTh?.Interrupt();
                    receiveTh = null;
                    stream?.Close();
                    tcpClient?.Close();
                    stream = null;
                    tcpClient = null;
                    info.msg = "已断开连接";
                    LogInfoDisplay?.Invoke(info);
                }
                catch (Exception ex)
                {
                    info.msg = $"断开异常: {ex.Message}";
                    LogInfoDisplay?.Invoke(info);
                }
            }
        }
        /// <summary>
        /// 处理自动重连逻辑(避免阻塞主线程)
        /// </summary>
        private void HandleReconnection()
        {
            if (!AutoReconnect || string.IsNullOrEmpty(currentIp)) return;
            Task.Run(() =>
            {
                int attempts = 0;
                while (!connected && !disposed && attempts < maxReconnectAttempts)
                {
                    Thread.Sleep(ReconnectInterval);
                    try
                    {
                        if (Connect(currentIp, currentPort))
                        {
                            info.msg = "自动重连成功";
                            LogInfoDisplay?.Invoke(info);
                            break;
                        }
                        attempts++;
                    }
                    catch { }
                }
            });
        }
        #endregion
        #region 接收线程
        /// <summary>
        /// 启动后台接收线程
        /// </summary>
        private void StartReceiveThread()
        {
            receiveTh = new Thread(ReceiveThreadProc)
            {
                IsBackground = true,
                Name = "ModbusTCP接收线程"
            };
            receiveTh.Start();
        }
        /// <summary>
        /// 接收线程主体:持续监听数据
        /// </summary>
        private void ReceiveThreadProc()
        {
            while (connected && !disposed)
            {
                try
                {
                    if (stream.DataAvailable)
                    {
                        // 先读取 MBAP 头(前6字节)
                        int len = stream.Read(receiveBuffer, 0, 6);
                        if (len < 6) continue;
                        // 解析协议数据单元长度(大端)
                        int pduLength = (receiveBuffer[4] << 8) | receiveBuffer[5];
                        int totalLength = 6 + pduLength;
                        // 读取剩余部分
                        int read = 0;
                        while (read < pduLength)
                        {
                            int n = stream.Read(receiveBuffer, 6 + read, pduLength - read);
                            if (n <= 0) throw new IOException("连接中断");
                            read += n;
                        }
                        ProcessReceivedData(receiveBuffer, totalLength);
                    }
                    else
                    {
                        Thread.Sleep(10); // 小延时避免CPU空转
                    }
                }
                catch (SocketException ex)
                {
                    // 连接被对端关闭或中断
                    if (ex.SocketErrorCode == SocketError.ConnectionReset ||
                        ex.SocketErrorCode == SocketError.ConnectionAborted)
                    {
                        info.msg = "连接被远程关闭或异常断开";
                        LogInfoDisplay?.Invoke(info);
                        connected = false;
                        HandleReconnection();
                    }
                    else
                    {
                        info.msg = $"Socket异常: {ex.Message}";
                        LogInfoDisplay?.Invoke(info);
                    }
                }
                catch (Exception ex)
                {
                    if (connected)
                    {                        
                        info.msg = $"接收数据异常: {ex.Message}";
                        LogInfoDisplay?.Invoke(info);
                        connected = false;
                        HandleReconnection();
                    }
                    break;
                }
            }
        }
        /// <summary>
        /// 处理接收到的数据包
        /// </summary>
        private void ProcessReceivedData(byte[] data, int length)
        {
            lock (responseLock)
            {
                currentResponse = new byte[length];
                Array.Copy(data, 0, currentResponse, 0, length);
                responseBytes = currentResponse;
                receiveEvent.Set(); // 通知等待响应的线程
                // 触发接收事件(Hex字符串格式)
                if (returnReceiveEvent != null)
                {
                    string hexString = BitConverter.ToString(data, 0, length).Replace("-", " ");
                    returnReceiveEvent(hexString);
                }
            }
        }
        #endregion
        #region 发送请求
        /// <summary>
        /// 发送 Modbus 请求并等待响应
        /// </summary>
        /// <param name="request">请求报文</param>
        /// <param name="expectedResponseLength">期望响应长度(用于校验)</param>
        /// <returns>响应字节数组,失败返回 null</returns>
        private async Task<byte[]> SendRequestAsync(byte[] request, int expectedResponseLength)
        {
            try
            {
                // 假设 tcpClient 已连接,networkStream = tcpClient.GetStream()
                if (stream == null || !stream.CanWrite) return null;
                // 设置事务ID(大端字节序)
                ushort transactionId = GenerateTransactionId(); // 自增或随机生成
                request[0] = (byte)(transactionId >> 8);
                request[1] = (byte)(transactionId & 0xFF);
                // 发送请求
                await stream.WriteAsync(request, 0, request.Length).ConfigureAwait(false);
                // 读取响应头(至少 9 字节 MBAP + PDU header)
                byte[] header = new byte[9];
                int read = await ReadExactAsync(stream, header, 0, 9).ConfigureAwait(false);
                if (read != 9) return null;
                // 解析后续长度(第5-6字节)
                int pduLength = (header[4] << 8) | header[5]; // 后续数据长度
                int totalResponseLength = 6 + pduLength;      // MBAP(6) + PDU
                if (totalResponseLength > expectedResponseLength)
                {
                    // 扩展缓冲区以接收完整响应
                    byte[] fullResponse = new byte[totalResponseLength];
                    Array.Copy(header, 0, fullResponse, 0, 9);
                    int remaining = totalResponseLength - 9;
                    read = await ReadExactAsync(stream, fullResponse, 9, remaining).ConfigureAwait(false);
                    if (read != remaining) return null;
                    return fullResponse;
                }
                return header; // 如果已足够
            }
            catch (Exception ex)
            {
                Console.WriteLine("通信异常: " + ex.Message);
                connected = false;
                return null;
            }
        }
        /// <summary>
        /// 确保异步读取指定数量的字节
        /// </summary>
        private async Task<int> ReadExactAsync(NetworkStream stream, byte[] buffer, int offset, int count)
        {
            int totalRead = 0;
            while (totalRead < count)
            {
                int read = await stream.ReadAsync(buffer, offset + totalRead, count - totalRead).ConfigureAwait(false);
                if (read == 0) break; // 连接关闭
                totalRead += read;
            }
            return totalRead;
        }
        #endregion
        #region 地址解析
        /// <summary>
        /// 解析地址字符串如 "D100" -> 实际地址 99(若偏移-1)
        /// </summary>
        private ushort ParseAddress(string address)
        {
            if (string.IsNullOrEmpty(address) || address.Length < 2)
                throw new ArgumentException("地址格式错误");
            char type = char.ToUpper(address[0]);
            string numPart = address.Substring(1).Split('.')[0]; // 忽略位索引
            if (!int.TryParse(numPart, out int rawAddr))
                throw new ArgumentException("地址数值无效");
            int baseAddress;
            switch (type)
            {
                case 'D':
                case 'M':
                case 'X':
                case 'Y':
                    baseAddress = 0x0000;
                    break;
                default:
                    throw new ArgumentException($"不支持的地址类型: {type}");
            }
            int finalAddr = baseAddress + rawAddr + AddressOffset;
            if (finalAddr < 0 || finalAddr > 65535)
                throw new ArgumentException("地址超出范围");
            return (ushort)finalAddr;
        }
        #endregion
        #region 读取线圈寄存器(M寄存器)
        /// <summary>
        /// 读取线圈寄存器(功能码01)
        /// </summary>
        /// <param name="ID">客户端ID</param>
        /// <param name="address">地址</param>
        /// <param name="length">长度</param>
        /// <returns>值</returns>
        public async Task<bool[]> ReadCoilsAsync(byte ID, string address, int length)
        {
            if (length <= 0) length = 1; 
            if (length > 2048) length = 2048;
            ushort addr = ParseAddress(address);
            int byteCount = (length + 7) / 8;
            byte[] request = new byte[12];
            // 构建 Modbus TCP 请求报文
            request[0] = 0; request[1] = 0;  //----------事务ID(由 SendRequestAsync 填充或自动生成)
            request[2] = 0x00; request[3] = 0x00;  //----协议ID
            request[4] = 0x00; request[5] = 0x06;  //----后续长度:6字节(PDU)
            request[6] = ID;  //-------------------------单元标识符ID
            request[7] = 0x01;  //-----------------------功能码(读线圈)
            request[8] = (byte)(addr >> 8);  //----------起始地址高字节
            request[9] = (byte)(addr & 0xFF);  //--------起始地址低字节
            request[10] = (byte)(length >> 8);  //-------数量高字节
            request[11] = (byte)(length & 0xFF);  //-----数量低字节
            byte[] response = await SendRequestAsync(request, 9 + byteCount).ConfigureAwait(false);
            if (response == null || response.Length < 9 + byteCount) return null;
            bool[] result = new bool[length];
            for (int i = 0; i < length; i++)
            {
                int byteIdx = i / 8;
                int bitIdx = i % 8;
                result[i] = (response[9 + byteIdx] & (1 << bitIdx)) != 0;
            }
            return result;
        }
        #endregion
        #region 读取输入状态
        /// <summary>
        /// 读取输入状态(功能码02)
        /// </summary>
        /// <param name="ID">客户端ID</param>
        /// <param name="address">地址</param>
        /// <param name="length">长度</param>
        /// <returns>值</returns>
        public async Task<bool[]> ReadDiscreteInputsAsync(byte ID, string address, int length)
        {
            if (length <= 0) length = 1;
            if (length > 2048) length = 2048;
            ushort addr = ParseAddress(address);
            int byteCount = (length + 7) / 8;
            byte[] request = new byte[12];
            // 构建 Modbus TCP 请求报文
            request[0] = 0; request[1] = 0;  //----------事务ID(由 SendRequestAsync 填充或自动生成)
            request[2] = 0x00; request[3] = 0x00;  //----协议ID
            request[4] = 0x00; request[5] = 0x06;  //----后续长度:6字节(PDU)
            request[6] = ID;  //-------------------------单元标识符ID
            request[7] = 0x02;  //-----------------------功能码(读离散输入)
            request[8] = (byte)(addr >> 8);  //----------起始地址高字节
            request[9] = (byte)(addr & 0xFF);  //--------起始地址低字节
            request[10] = (byte)(length >> 8);  //-------数量高字节
            request[11] = (byte)(length & 0xFF);  //-----数量低字节
            byte[] response = await SendRequestAsync(request, 9 + byteCount).ConfigureAwait(false);
            if (response == null || response.Length < 9 + byteCount) return null;
            bool[] result = new bool[length];
            for (int i = 0; i < length; i++)
            {
                int byteIdx = i / 8;
                int bitIdx = i % 8;
                result[i] = (response[9 + byteIdx] & (1 << bitIdx)) != 0;
            }
            return result;
        }
        #endregion
        #region 读取保持寄存器(D寄存器)        
        
        /// <summary>
        /// 读取保持寄存器(功能码03)
        /// </summary>
        /// <param name="ID">客户端ID</param>
        /// <param name="address">地址</param>
        /// <param name="length">长度</param>
        /// <param name="type">类型</param>
        /// <returns>值</returns>
        public async Task<int[]> ReadHoldingRegistersAsync(byte ID, string address, int length, DataType type = DataType.字)
        {
            if (length <= 0) length = 1;
            if (length > 125) length = 125;
            ushort addr = ParseAddress(address);
            ushort regCount = (ushort)(length * (ushort)type);
            byte[] request = new byte[12];
            // 构建 Modbus TCP 请求报文
            request[0] = 0; request[1] = 0;  //----------事务ID(由 SendRequestAsync 填充或自动生成)
            request[2] = 0x00; request[3] = 0x00;  //----协议ID
            request[4] = 0x00; request[5] = 0x06;  //----后续长度:6字节(PDU)
            request[6] = ID;  //-------------------------单元标识符ID
            request[7] = 0x03;  //-----------------------功能码(读保持寄存器)
            request[8] = (byte)(addr >> 8);  //----------起始地址高字节
            request[9] = (byte)(addr & 0xFF);  //--------起始地址低字节
            request[10] = (byte)(regCount >> 8);  //-----数量高字节
            request[11] = (byte)(regCount & 0xFF);  //---数量低字节
            byte[] response = await SendRequestAsync(request, 9 + regCount * 2).ConfigureAwait(false);
            if (response == null || response.Length < 9 + regCount * 2) return null;
            return ParseRegisterResponse(response, length, type);
        }
        /// <summary>
        /// 解析寄存器响应(16位和32位)
        /// </summary>
        private int[] ParseRegisterResponse(byte[] response, int length, DataType type)
        {
            int[] result = new int[length];
            if (type == DataType.字)
            {
                for (int i = 0; i < length; i++)
                {
                    int dataIndex = 9 + i * 2;
                    if (dataIndex + 1 < response.Length)
                    {
                        ushort value = (ushort)((response[dataIndex] << 8) | response[dataIndex + 1]);
                        result[i] = (short)value;  // 直接转换为有符号short
                    }
                }
            }
            else //双字
            {
                for (int i = 0; i < length; i++)
                {
                    int dataIndex = 9 + i * 4;
                    if (dataIndex + 3 < response.Length)
                    {
                        uint value = ((uint)response[dataIndex] << 24) |
                                     ((uint)response[dataIndex + 1] << 16) |
                                     ((uint)response[dataIndex + 2] << 8) |
                                      response[dataIndex + 3];
                        result[i] = (int)value;  // 自动处理补码
                    }
                }
            }
            return result;
        }
        #endregion
        #region 读取输入寄存器
        /// <summary>
        /// 读取输入寄存器(功能码04)
        /// </summary>
        /// <param name="ID">客户端ID</param>
        /// <param name="address">地址</param>
        /// <param name="length">长度</param>
        /// <param name="type">类型</param>
        /// <returns>值</returns>
        public async Task<int[]> ReadInputRegistersAsync(byte ID, string address, int length, DataType type = DataType.字) 
        {
            if (length <= 0) length = 1;
            if (length > 125) length = 125;
            ushort addr = ParseAddress(address);
            ushort regCount = (ushort)(length * (ushort)type);
            byte[] request = new byte[12];
            // 构建 Modbus TCP 请求报文
            request[0] = 0; request[1] = 0;  //----------事务ID(由 SendRequestAsync 填充或自动生成)
            request[2] = 0x00; request[3] = 0x00;  //----协议ID
            request[4] = 0x00; request[5] = 0x06;  //----后续长度:6字节(PDU)
            request[6] = ID;  //-------------------------单元标识符ID
            request[7] = 0x04;  //-----------------------功能码(读输入寄存器)
            request[8] = (byte)(addr >> 8);  //----------起始地址高字节
            request[9] = (byte)(addr & 0xFF);  //--------起始地址低字节
            request[10] = (byte)(regCount >> 8);  //-----数量高字节
            request[11] = (byte)(regCount & 0xFF);  //---数量低字节
            byte[] response = await SendRequestAsync(request, 9 + regCount * 2).ConfigureAwait(false);
            if (response == null || response.Length < 9 + regCount * 2) return null;
            return ParseRegisterResponse(response, length, type);
        }
        #endregion
        #region 写入单个线圈寄存器值(M寄存器)
        /// <summary>
        /// 写入单个线圈寄存器值(功能码05)
        /// </summary>
        /// <param name="ID">客户端ID</param>
        /// <param name="address">地址</param>
        /// <param name="value">值</param>
        public async Task<bool> WriteSingleCoilsAsync(byte ID, string address, bool value)
        {
            if (!connected) return false;
            ushort addr = ParseAddress(address);
            byte[] request = new byte[12];
            // 构建 Modbus TCP 请求报文
            request[0] = 0; request[1] = 0;  //----------事务ID(由 SendRequestAsync 填充或自动生成)
            request[2] = 0x00; request[3] = 0x00;  //----协议ID
            request[4] = 0x00; request[5] = 0x06;  //----后续长度:6字节(PDU)
            request[6] = ID;  //-------------------------单元标识符ID
            request[7] = 0x05;  //-----------------------功能码(写单个线圈)
            request[8] = (byte)(addr >> 8);  //----------起始地址高字节
            request[9] = (byte)(addr & 0xFF);  //--------起始地址低字节
            request[10] = (byte)(value ? 0xFF : 0x00); //数据(FF表示ON,00表示OFF)
            request[11] = 0x00;  //----------------------数据(固定0x00)            
            try
            {
                byte[] response = await SendRequestAsync(request, 12).ConfigureAwait(false);
                return response != null && response.Length >= 12 &&
                       response[7] == 0x05 && (response[8] << 8 | response[9]) == addr; 
            }
            catch { return false; }                      
        }
        #endregion
        #region 写入单个保持寄存器值(D寄存器)
        /// <summary>
        /// 写入单个保持寄存器值(功能码06)(功能码16)
        /// </summary>
        /// <param name="ID">设备ID</param>
        /// <param name="address">地址</param>
        /// <param name="value">值(16位或32位)</param>
        /// <param name="type">数据类型(字=16位,双字=32位)</param>
        /// <returns>是否写入成功</returns>
        public async Task<bool> WriteSingleRegistersAsync(byte ID, string address, int value, DataType type = DataType.字)
        {
            if (!connected) return false;
            if (type == DataType.字)
            {                
                return await WriteSingleRegister16(ID, address, (short)value);
            }
            else
            {
                return await WriteDoubleRegister32(ID, address, (int)value);
            }
        }
        /// <summary>
        /// 16位写入实现(功能码06)
        /// </summary>
        /// <param name="ID"></param>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        private async Task<bool> WriteSingleRegister16(byte ID, string address, short value)
        {
            ushort addr = ParseAddress(address);
            ushort uvalue = (ushort)value;
            byte[] request = new byte[12];
            // 构建 Modbus TCP 请求报文
            request[0] = 0; request[1] = 0;  //----------事务ID(由 SendRequestAsync 填充或自动生成)
            request[2] = 0x00; request[3] = 0x00;  //----协议ID
            request[4] = 0x00; request[5] = 0x06;  //----后续长度:6字节(PDU)
            request[6] = ID;  //-------------------------单元标识符ID
            request[7] = 0x06;  //-----------------------功能码(写16位保存寄存器)
            request[8] = (byte)(addr >> 8);  //----------起始地址高字节
            request[9] = (byte)(addr & 0xFF);  //--------起始地址低字节
            request[10] = (byte)(uvalue >> 8);  //-------数量高字节
            request[11] = (byte)(uvalue & 0xFF);  //-----数量低字节
            
            byte[] response = await SendRequestAsync(request, 12).ConfigureAwait(false);
            return response != null && response.Length >= 12 &&
                   response[7] == 0x06 && (response[8] << 8 | response[9]) == addr;
        }
        /// <summary>
        /// 32位写入实现(功能码16)
        /// </summary>
        /// <param name="ID"></param>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        private async Task<bool> WriteDoubleRegister32(byte ID, string address, int value)
        {
            return await WriteMultipleRegistersAsync(ID, address, new[] { (short)(value >> 16), (short)(value & 0xFFFF) });
        }
        #endregion
        #region 写入多个线圈寄存器值(M寄存器)
        /// <summary>
        /// 写入多个线圈寄存器值(功能码15)- 所有线圈写入相同值
        /// </summary>
        /// <param name="ID">设备ID</param>
        /// <param name="address">起始地址(如"M100")</param>
        /// <param name="length">写入的线圈数量</param>
        /// <param name="value">所有线圈的状态(true=ON, false=OFF)</param>
        /// <returns>是否写入成功</returns>
        /// <example>
        /// WriteMultipleCoils(1, "M100", 2, true); 
        /// // 写入M100=true, M101=true
        /// WriteMultipleCoils(1, "M100", 5, false); 
        /// // 写入M100~M104全部为false
        /// </example>
        public async Task<bool> WriteMultipleCoilsAsync(byte ID, string address, int length, bool value)
        {
            if (!connected) return false;
            bool[] values = new bool[length];
            for (int i = 0; i < length; i++) values[i] = value;
            return await WriteMultipleCoilsAsync(ID, address, values);
        }
        /// <summary>
        /// 写入多个线圈寄存器值(bool数组版本)- 每个线圈独立控制
        /// </summary>
        /// <param name="ID">设备ID</param>
        /// <param name="address">起始地址</param>
        /// <param name="values">每个线圈的状态数组</param>
        /// <returns>是否写入成功</returns>
        /// <example>
        /// WriteMultipleCoils(1, "M100", new bool[] { true, false, true });
        /// // 写入M100=true, M101=false, M102=true
        /// </example>
        public async Task<bool> WriteMultipleCoilsAsync(byte ID, string address, bool[] values)
        {
            if (!connected) return false;
            ushort addr = ParseAddress(address);
            int byteCount = (values.Length + 7) / 8;
            byte[] coilBytes = new byte[byteCount];
            for (int i = 0; i < values.Length; i++)
            {
                if (values[i])
                    coilBytes[i / 8] |= (byte)(1 << (i % 8));
            }
            byte[] request = new byte[13 + byteCount];
            // 构建 Modbus TCP 请求报文
            request[0] = 0; request[1] = 0;  //----------事务ID(由 SendRequestAsync 填充或自动生成)
            request[2] = 0x00; request[3] = 0x00;  //----协议ID
            request[4] = (byte)((request.Length - 6) >> 8);
            request[5] = (byte)((request.Length - 6) & 0xFF);
            request[6] = ID;  //-------------------------单元标识符ID
            request[7] = 0x0F;  //-----------------------功能码(写多线圈寄存器)
            request[8] = (byte)(addr >> 8);  //----------起始地址高字节
            request[9] = (byte)(addr & 0xFF);  //--------起始地址低字节
            request[10] = (byte)(values.Length >> 8);  //数量高字节
            request[11] = (byte)(values.Length & 0xFF);//数量低字节
            request[12] = (byte)(values.Length * 2);
            request[12] = (byte)byteCount;
            Array.Copy(coilBytes, 0, request, 13, byteCount);
            byte[] response = await SendRequestAsync(request, 12).ConfigureAwait(false);
            return response != null && response.Length >= 12;
        }
        #endregion
        #region 写入多个保持寄存器值(D寄存器)
        /// <summary>
        /// 写入多个保持寄存器值(功能码16) - 所有寄存器写入相同值
        /// </summary>
        /// <param name="ID">设备ID</param>
        /// <param name="address">起始地址(如"D100")</param>
        /// <param name="length">写入的寄存器数量</param>
        /// <param name="value">所有寄存器的值</param>
        /// <param name="type">数据类型(字=16位,双字=32位)</param>
        /// <returns>是否写入成功</returns>
        /// <example>
        /// WriteMultipleRegister(1, "D100", 3, 100); 
        /// // 写入D100=100, D101=100, D102=100
        /// WriteMultipleRegister(1, "D200", 2, 123456789, ReadTypeEnum.双字); 
        /// // 写入D200-D201=123456789, D202-D203=123456789
        /// </example>
        public async Task<bool> WriteMultipleRegistersAsync(byte ID, string address, int length, int value, DataType type = DataType.字)
        {
            if (!connected) return false;
            if (type == DataType.字)
            {
                short[] arr = new short[length];
                for (int i = 0; i < length; i++) arr[i] = (short)value;
                return await WriteMultipleRegistersAsync(ID, address, arr);
            }
            else
            {
                short[] arr = new short[length * 2];
                for (int i = 0; i < length; i++)
                {
                    arr[i * 2] = (short)(value >> 16);
                    arr[i * 2 + 1] = (short)(value & 0xFFFF);
                }
                return await WriteMultipleRegistersAsync(ID, address, arr);
            }
        }
        /// <summary>
        /// 写入多个保持寄存器值(功能码16)
        /// </summary>
        /// <param name="ID"></param>
        /// <param name="address"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        private async Task<bool> WriteMultipleRegistersAsync(byte ID, string address, short[] values)
        {
            ushort addr = ParseAddress(address);
            byte[] request = new byte[13 + values.Length * 2];
            // 构建 Modbus TCP 请求报文
            request[0] = 0; request[1] = 0;  //----------事务ID(由 SendRequestAsync 填充或自动生成)
            request[2] = 0x00; request[3] = 0x00;  //----协议ID
            request[4] = (byte)((request.Length - 6) >> 8);
            request[5] = (byte)((request.Length - 6) & 0xFF);
            request[6] = ID;  //-------------------------单元标识符ID
            request[7] = 0x10;  //-----------------------功能码(写多保存寄存器)
            request[8] = (byte)(addr >> 8);  //----------起始地址高字节
            request[9] = (byte)(addr & 0xFF);  //--------起始地址低字节
            request[10] = (byte)(values.Length >> 8);  //数量高字节
            request[11] = (byte)(values.Length & 0xFF);//数量低字节
            request[12] = (byte)(values.Length * 2);
            for (int i = 0; i < values.Length; i++)
            {
                request[13 + i * 2] = (byte)(values[i] >> 8);
                request[13 + i * 2 + 1] = (byte)(values[i] & 0xFF);
            }
            byte[] response = await SendRequestAsync(request, 12).ConfigureAwait(false);
            return response != null && response.Length >= 12 && response[7] == 0x10 &&
                   (response[8] << 8 | response[9]) == addr &&
                   (response[10] << 8 | response[11]) == values.Length;
        }
        #endregion
        #region 客户端关闭
        /// <summary>
        /// 释放所有资源
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (disposed) return;
            disposed = true;
            if (disposing)
            {
                // 释放托管资源
                heartbeatTimer?.Dispose();
                receiveEvent?.Dispose();
                stream?.Dispose();
                tcpClient?.Dispose();
            }
        }        
        #endregion
    }
    #endregion该代码的问题
					最新发布