Search code examples
c#modbus

Modbus function 0x06


Faced a problem. There is a 0x03 function, but I need to redo it in 0x06, I don’t understand how to do it.

I know that function 06 does not have a variable part. The value of one register is always transferred to it. But I can not understand what needs to be corrected. Please, help.

Here I create a package for functions:

 private void BuildMessage(byte address, byte type, ushort start, ushort registers, ref byte[] message)
                {
                    if (type == 3 || type == 16)
                    {
                        //Array to receive CRC bytes:
                        byte[] CRC = new byte[2];

                        message[0] = address;
                        message[1] = type;
                        message[2] = (byte)(start >> 8);
                        message[3] = (byte)start;
                        message[4] = (byte)(registers >> 8);
                        message[5] = (byte)registers;

                        GetCRC(message, ref CRC);
                        message[message.Length - 2] = CRC[0];
                        message[message.Length - 1] = CRC[1];
                    }
                    else if (type == 6)
                    {
                        byte[] CRC = new byte[2];

                        message[0] = address;
                        message[1] = type;
                        message[2] = (byte)(start >> 8);
                        message[3] = (byte)start;
                        message[4] = (byte)(registers >> 8);
                        message[5] = (byte)registers;

                        GetCRC(message, ref CRC);
                        message[6] = CRC[0];
                        message[7] = CRC[1];
                    }
        }

This is my function number 3:

 public bool SendFunc(int funcNumer, string connectType, byte address, ushort start, ushort registers, ref short[] values)
            {
                #region №3
                if (funcNumer == 3)
                {
                    #region serial-port
                    if (connectType.Equals("COM"))
                    {
                        //Ensure port is open:
                        if (sp.IsOpen)
                        {
                            //Clear in/out buffers:
                            sp.DiscardOutBuffer();
                            sp.DiscardInBuffer();
                            //Function 3 request is always 8 bytes:
                            byte[] message = new byte[8];
                            //Function 3 response buffer:
                            byte[] response = new byte[5 + 2 * registers];
                            //Build outgoing modbus message:
                            BuildMessage(address, (byte)3, start, registers, ref message);
                            //Send modbus message to Serial Port:
                            try
                            {
                                sp.Write(message, 0, message.Length);
                                GetResponse("COM", ref response);
                            }
                            catch (Exception err)
                            {
                                modbusStatus = "" + err.Message;
                                return false;
                            }
                            //Evaluate message:
                            if (CheckResponse(response))
                            {
                                //Return requested register values:
                                for (int i = 0; i < (response.Length - 5) / 2; i++)
                                {
                                    values[i] = response[2 * i + 3];
                                    values[i] <<= 8;
                                    values[i] += response[2 * i + 4];
                                }
                                modbusStatus = "";
                                return true;
                            }
                            else
                            {
                                modbusStatus = "";
                                return false;
                            }
                        }
                        else
                        {
                            modbusStatus = "";
                            return false;
                        }
                    }

And here I am trying to implement function number 6:

if (funcNumer == 6)
            {
                #region serial-port
                if (connectType.Equals("COM"))
                {
                    //Ensure port is open:
                    if (sp.IsOpen)
                    {
                        //Clear in/out buffers:
                        sp.DiscardOutBuffer();
                        sp.DiscardInBuffer();
                        //Function 3 request is always 8 bytes:
                        byte[] message = new byte[8];
                        //Function 3 response buffer:
                        byte[] response = new byte[5 + 2 * registers];
                        //Build outgoing modbus message:
                        BuildMessage(address, (byte)6, start, registers, ref message);
                        //Send modbus message to Serial Port:
                        try
                        {
                            sp.Write(message, 0, message.Length);
                            GetResponse("COM", ref response);
                        }
                        catch (Exception err)
                        {
                            modbusStatus = "" + err.Message;
                            return false;
                        }
                        //Evaluate message:
                        if (CheckResponse(response))
                        {
                            //Return requested register values:
                            for (int i = 0; i < (response.Length - 5) / 2; i++)
                            {
                                values[i] = response[2 * i + 3];
                                values[i] <<= 8;
                                values[i] += response[2 * i + 4];
                            }
                            modbusStatus = "";
                            return true;
                        }
                        else
                        {
                            modbusStatus = "";
                            return false;
                        }
                    }
                    else
                    {
                        modbusStatus = "";
                        return false;
                    }
                }

This is my function to check the response:

 private bool CheckResponse(byte[] response)
        {
            //Perform a basic CRC check:
            byte[] CRC = new byte[2];
            GetCRC(response, ref CRC);
            if (CRC[0] == response[response.Length - 2] && CRC[1] == response[response.Length - 1])
                return true;
            else
                return false;
        }

This is my function for get response:

private void GetResponse(string connect, ref byte[] response)
        {
            if (connect.Equals("COM"))
            {
                for (int i = 0; i < response.Length; i++)
                {
                    response[i] = (byte)(sp.ReadByte());
                }
            }
            else if (connect.Equals("TCP"))
            {
                NetworkStream stream = tcpClient.GetStream();

                for (int i = 0; i < response.Length; i++)
                {
                    response[i] = (byte)(stream.ReadByte());
                }
            }
            else
            {

            }            
        }

Solution

  • The difference between Modbus function 0x03 and 0x06 is actually the part of the code you did not show on your question: CheckResponse(response).

    Function 0x03 reads a number of registers, and the values in those registers (coming from the slave) are included in the response.

    Function 0x06 writes a single register and gives an echo back. So the response is the same as the query.

    With that information, it should be easy to modify your code: remove the for loop where you retrieve the register values.

    Other than that you might need to modify your CheckResponse() function too, but that should also be quite straight forward: just check the response is exactly the same as the query (message).

    EDIT: if your CheckResponse()` function only checks for the correct CRC on the responses I suppose you can keep it as it is.