[Modbus] 如何 用 C# 開發 Modbus Master Protocol - (11) 實作 HexModbusDataConvert

[Modbus] 如何 用 C# 開發 Modbus Master Protocol - (11) 實作 HexModbusDataConvert

續上篇,產出的資料若都是 byte[] 實在很難閱讀,所以這個 HexModbusDataConvert  類別專處理資料格式轉換

image

 

這只是很簡單的進制轉換,要參考的資料很多

[C#.NET] 開發通訊協定必須要會的技巧

[C#.NET] 處理通訊協定的事前準備

[C#.NET] 浮點數 轉 Hexadecimal

[C#.NET] Hexadecimal 字串格式轉時間格式

[C#][VB.NET] 進制轉換 (2進制、8進制、16進制)轉10進制

[VB6][C#][VB.Net] 進制轉換,2進制轉(10進制、8進制、16進制)

 


{
    public override byte[] ResultArray { get; internal set; }

    public override IEnumerable<long> ToDecimal(byte[] ResultArray, EnumModbusIntegralUnit Unit)
    {
        var length = (int)Unit;
        if (ResultArray == null)
        {
            throw new ArgumentNullException("ResultArray");
        }
        if (ResultArray.Length <= 0 || ResultArray.Length < length)
        {
            throw new FormatException("ResultArray");
        }
        this.ResultArray = ResultArray;
        List<long> resultList = new List<long>();

        for (int i = 0; i < ResultArray.Length; i = i + length)
        {
            using (MemoryStream memory = new MemoryStream())
            {
                memory.Write(ResultArray, i, length);
                var tempArray = memory.ToArray();

                long result = 0;

                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(tempArray);
                }
                switch (Unit)
                {
                    case EnumModbusIntegralUnit.Byte:
                        result = tempArray[0];
                        break;

                    case EnumModbusIntegralUnit.Word:
                        result = BitConverter.ToInt16(tempArray, 0);
                        break;

                    case EnumModbusIntegralUnit.DWord:
                        result = BitConverter.ToInt32(tempArray, 0);
                        break;

                    case EnumModbusIntegralUnit.QWord:
                        result = BitConverter.ToInt64(tempArray, 0);
                        break;

                    default:
                        throw new ArgumentOutOfRangeException("Unit");
                }
                resultList.Add(result);
            }
        }

        return resultList;
    }

    public override IEnumerable<long> ToOctal(byte[] ResultArray, EnumModbusIntegralUnit Unit)
    {
        var length = (int)Unit;
        if (ResultArray == null)
        {
            throw new ArgumentNullException("ResultArray");
        }
        if (ResultArray.Length <= 0 || ResultArray.Length < length)
        {
            throw new FormatException("ResultArray");
        }
        this.ResultArray = ResultArray;
        List<long> resultList = new List<long>();

        for (int i = 0; i < ResultArray.Length; i = i + length)
        {
            using (MemoryStream memory = new MemoryStream())
            {
                memory.Write(ResultArray, i, length);
                var tempArray = memory.ToArray();
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(tempArray);
                }

                switch (Unit)
                {
                    case EnumModbusIntegralUnit.Byte:
                        var dec = tempArray[0];
                        var oct = int.Parse(Convert.ToString(dec, 8));
                        resultList.Add(oct);
                        break;

                    case EnumModbusIntegralUnit.Word:
                        var decShort = BitConverter.ToInt16(tempArray, 0);
                        var octShort = int.Parse(Convert.ToString(decShort, 8));
                        resultList.Add(octShort);
                        break;

                    case EnumModbusIntegralUnit.DWord:
                        var decInt = BitConverter.ToInt32(tempArray, 0);
                        var octInt = long.Parse(Convert.ToString(decInt, 8));
                        resultList.Add(octInt);
                        break;

                    case EnumModbusIntegralUnit.QWord:
                        var decLong = BitConverter.ToInt32(tempArray, 0);
                        var octLong = long.Parse(Convert.ToString(decLong, 8));
                        resultList.Add(octLong);
                        break;

                    default:
                        throw new ArgumentOutOfRangeException("Unit");
                }
            }
        }

        return resultList;
    }

    public override IEnumerable<string> ToHexadecimal(byte[] ResultArray, EnumModbusIntegralUnit Unit)
    {
        var length = (int)Unit;
        if (ResultArray == null)
        {
            throw new ArgumentNullException("ResultArray");
        }
        if (ResultArray.Length <= 0 || ResultArray.Length < length)
        {
            throw new FormatException("ResultArray");
        }
        this.ResultArray = ResultArray;
        List<string> resultList = new List<string>();
        for (int i = 0; i < ResultArray.Length; i = i + length)
        {
            using (MemoryStream memory = new MemoryStream())
            {
                memory.Write(ResultArray, i, length);
                var tempArray = memory.ToArray();
                var result = BitConverter.ToString(tempArray).Replace("-", "");
                resultList.Add(result);
            }
        }
        return resultList;
    }

    public override IEnumerable<string> ToBinary(byte[] ResultArray, EnumModbusIntegralUnit Unit)
    {
        var length = (int)Unit;
        if (ResultArray == null)
        {
            throw new ArgumentNullException("ResultArray");
        }
        if (ResultArray.Length <= 0 || ResultArray.Length < length)
        {
            throw new FormatException("ResultArray");
        }
        this.ResultArray = ResultArray;
        List<string> resultList = new List<string>();
        for (int i = 0; i < ResultArray.Length; i = i + length)
        {
            using (MemoryStream memory = new MemoryStream())
            {
                memory.Write(ResultArray, i, length);
                var tempArray = memory.ToArray();
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(tempArray);
                }

                var bin = "";
                switch (Unit)
                {
                    case EnumModbusIntegralUnit.Byte:
                        bin = Convert.ToString(tempArray[0], 2).PadLeft(8, '0');
                        break;

                    case EnumModbusIntegralUnit.Word:
                        var decShort = BitConverter.ToInt16(tempArray, 0);
                        bin = Convert.ToString(decShort, 2).PadLeft(16, '0');
                        break;

                    case EnumModbusIntegralUnit.DWord:
                        var decInt = BitConverter.ToInt32(tempArray, 0);
                        bin = Convert.ToString(decInt, 2).PadLeft(32, '0');
                        break;

                    case EnumModbusIntegralUnit.QWord:
                        var decLong = BitConverter.ToInt64(tempArray, 0);
                        bin = Convert.ToString(decLong, 2).PadLeft(64, '0');
                        break;

                    default:
                        throw new ArgumentOutOfRangeException("Unit");
                }

                resultList.Add(bin);
            }
        }

        return resultList;
    }

    public override IEnumerable<float> ToFloat(byte[] ResultArray)
    {
        var length = 4;
        if (ResultArray == null)
        {
            throw new ArgumentNullException("ResultArray");
        }
        if (ResultArray.Length <= 0 || ResultArray.Length < length)
        {
            throw new FormatException("ResultArray");
        }

        this.ResultArray = ResultArray;
        int count = ResultArray.Length / length;
        List<float> resultList = new List<float>();

        for (int i = 0; i < count * length; i = i + length)
        {
            using (MemoryStream memory = new MemoryStream())
            {
                memory.Write(ResultArray, i + 1, 1);
                memory.Write(ResultArray, i, 1);
                memory.Write(ResultArray, i + 3, 1);
                memory.Write(ResultArray, i + 2, 1);
                var resultArray = memory.ToArray();
                float result = BitConverter.ToSingle(resultArray, 0);
                resultList.Add(result);
            }
        }

        return resultList;
    }

    public override IEnumerable<double> ToDouble(byte[] ResultArray)
    {
        var length = 8;
        if (ResultArray == null)
        {
            throw new ArgumentNullException("ResultArray");
        }
        if (ResultArray.Length <= 0 || ResultArray.Length < length)
        {
            throw new FormatException("ResultArray");
        }

        this.ResultArray = ResultArray;
        int count = ResultArray.Length / length;
        List<double> resultList = new List<double>();

        for (int i = 0; i < count * length; i = i + length)
        {
            using (MemoryStream memory = new MemoryStream())
            {
                memory.Write(ResultArray, i + 1, 1);
                memory.Write(ResultArray, i, 1);
                memory.Write(ResultArray, i + 3, 1);
                memory.Write(ResultArray, i + 2, 1);

                memory.Write(ResultArray, i + 5, 1);
                memory.Write(ResultArray, i + 4, 1);
                memory.Write(ResultArray, i + 7, 1);
                memory.Write(ResultArray, i + 6, 1);
                var resultArray = memory.ToArray();
                double result = BitConverter.ToDouble(resultArray, 0);
                resultList.Add(result);
            }
        }

        return resultList;
    }
}

此類別,會用到的列舉


{
    Byte = 1, Word = 2, DWord = 4, QWord = 8
}

前面幾篇文章都會看的到的 ModbusUtility 類別,收納了一些雜像功能,不知如何分類的都被丟到這裡來,比如計算CRC / LRC


{
    public readonly static string ASCII_START_SYMBOL = ":";
    public readonly static string ASCII_END_SYMBOL = "\r\n";

    private CRCManager m_CrcManager = new CRCManager();
    private AbsCRCProvider m_CrcProvider;
    private string[] s_Symbol = new string[] { " ", ",", "-" };

    public string BytesToBinaryString(byte[] HexArray)
    {
        StringBuilder sb = new StringBuilder();

        foreach (var b in HexArray)
        {
            sb.Append(Convert.ToString(b, 2).PadLeft(8, '0'));
        }
        return sb.ToString();
    }

    public byte[] HexStringToBytes(string Hex)
    {
        string filter = s_Symbol.Aggregate(Hex, (current, symbol) => current.Replace(symbol, ""));

        return Enumerable.Range(0, filter.Length)
                          .Where(x => x % 2 == 0)
                          .Select(x => Convert.ToByte(filter.Substring(x, 2), 16))
                          .ToArray();
    }

    public string BytesToHexString(byte[] HexArray)
    {
        StringBuilder sb = new StringBuilder();
        foreach (var b in HexArray)
        {
            sb.Append(b.ToString("X2"));
        }
        return sb.ToString();
    }

    public string CalculateLRC(byte[] DataArray)
    {
        if (DataArray == null)
            throw new ArgumentNullException("data");

        byte lrc = 0;
        foreach (byte b in DataArray)
        {
            lrc += b;
        }

        lrc = (byte)((lrc ^ 0xFF) + 1);

        var hex = lrc.ToString("X2");
        return hex;
    }

    public byte[] CalculateCRC(byte[] DataArray)
    {
        if (m_CrcProvider == null)
        {
            m_CrcProvider = m_CrcManager.CreateCRCProvider(EnumCRCProvider.CRC16Modbus);
        }
        var crcArray = m_CrcProvider.GetCRC(DataArray).CrcArray;
        Array.Reverse(crcArray);
        return crcArray;
    }
}

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo