Search code examples
c#modbus

Decode byte array


I want to decode a byte array received from a modbus communication. This is the hex string representing the byte array:

01 11 0C 46 57 35 32 39 37 30 31 52 30 2E 35 FE 27

I want to split in 3 parts:

  1. 01 11 0C
  2. 46 57 35 32 39 37 30 31 52 30 2E 35
  3. FE 27

For transforming from byte to hex I use this method:

 #region ByteToHex
    /// <summary>
    /// method to convert a byte array into a hex string
    /// </summary>
    /// <param name="comByte">byte array to convert</param>
    /// <returns>a hex string</returns>
    public string ByteToHex(byte[] comByte)
    {
        //create a new StringBuilder object
        StringBuilder builder = new StringBuilder(comByte.Length * 3);
        //loop through each byte in the array
        foreach (byte data in comByte)
            //convert the byte to a string and add to the stringbuilder
            builder.Append(Convert.ToString(data, 16).PadLeft(2, '0').PadRight(3, ' '));
        //return the converted value
        return builder.ToString().ToUpper();
    }

How can I split the returned string from that method to return: the first 3 bytes are:

  1. Server id
  2. Function code
  3. Byte count

The next N bytes (see 3.) are the payload; the last 2 are a CRC16.

I need to find the payload; it is a string.


Solution

  • It makes little sense to turn the input into a hexadecimal string. You need to decode the information the bytes hold. What they hold exactly depends on the documentation, which you merely paraphrased. I'll take a shot at it:

    public class ModbusRequest
    {
        public byte ServerId { get; set; }
        public byte FunctionCode { get; set; }
        public string Payload { get; set; }
    }
    
    public ModbusRequest DecodeMessage(byte[] message)
    {
        var result = new ModbusRequest();
    
        // Simply copy bytes 0 and 1 into the destination structure.
        result.ServerId = message[0];
        result.FunctionCode = message[1];
    
        byte stringLength = message[2];
    
        // Assuming ASCII encoding, see docs.
        result.Payload = Encoding.ASCII.GetString(message, 3, stringLength);
    
        // Get the CRC bytes.
        byte[] crc = new byte[2];
        Buffer.BlockCopy(message, 4 + stringLength, crc, 0, 2);
    
        // TODO: verify CRC.
    
        return result;
    
    }
    

    To verify the CRC, find out which format is being used. I recommend using classless-hasher for implementing various CRC variants.