public static class ModbusHelper
{
    // 生成写单个线圈(功能码05)的Modbus指令
    public static string GenerateWriteSingleCoilCommand(byte deviceAddress, ushort coilAddress, bool value)
    {
        byte[] command = new byte[6];
        command[0] = deviceAddress;
        command[1] = 0x05; // 写单个线圈功能码
        command[2] = (byte)(coilAddress >> 8);
        command[3] = (byte)coilAddress;
        command[4] = value ? (byte)0xFF : (byte)0x00;
        command[5] = 0x00;

        // 计算CRC校验
        ushort crc = CalculateCRC(command, 6);
        byte[] crcBytes = BitConverter.GetBytes(crc);

        // 组合完整命令(包含CRC校验)
        byte[] fullCommand = new byte[8];
        Array.Copy(command, fullCommand, 6);
        fullCommand[6] = crcBytes[0]; // CRC低字节在前
        fullCommand[7] = crcBytes[1]; // CRC高字节在后

        // 转换为十六进制字符串
        return BitConverter.ToString(fullCommand).Replace("-", "");
    }

    // 验证Modbus响应是否有效
    public static bool ValidateResponse(string command, string response)
    {
        if (string.IsNullOrEmpty(response) || response.Length < 8)
            return false;

        // 解析响应字符串为字节数组
        byte[] responseBytes = StringToByteArray(response);

        // 从原始命令中提取设备地址
        byte deviceAddress = StringToByteArray(command.Substring(0, 2))[0];

        // 验证设备地址
        if (responseBytes[0] != deviceAddress)
            return false;

        // 验证功能码(响应中的功能码应与请求相同，若有异常则功能码最高位为1)
        byte requestFunctionCode = StringToByteArray(command.Substring(2, 2))[0];
        byte responseFunctionCode = responseBytes[1];

        // 检查是否为异常响应
        if ((responseFunctionCode & 0x80) != 0)
        {
            byte errorCode = responseBytes[2];
            Console.WriteLine($"Modbus异常响应 - 功能码: {requestFunctionCode}, 错误码: {errorCode}");
            return false;
        }

        // 验证功能码是否匹配
        if (responseFunctionCode != requestFunctionCode)
            return false;

        // 验证CRC校验
        ushort receivedCrc = (ushort)((responseBytes[responseBytes.Length - 2] << 8) | responseBytes[responseBytes.Length - 1]);
        ushort calculatedCrc = CalculateCRC(responseBytes, responseBytes.Length - 2);

        return receivedCrc == calculatedCrc;
    }

    // 计算Modbus RTU CRC校验
    private static ushort CalculateCRC(byte[] data, int length)
    {
        ushort crc = 0xFFFF;

        for (int i = 0; i < length; i++)
        {
            crc ^= data[i];

            for (int j = 0; j < 8; j++)
            {
                if ((crc & 0x0001) != 0)
                {
                    crc >>= 1;
                    crc ^= 0xA001;
                }
                else
                {
                    crc >>= 1;
                }
            }
        }

        return crc;
    }

    // 将十六进制字符串转换为字节数组
    private static byte[] StringToByteArray(string hex)
    {
        int length = hex.Length;
        byte[] bytes = new byte[length / 2];

        for (int i = 0; i < length; i += 2)
        {
            bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
        }

        return bytes;
    }
}