Modbus Communication

Combinu picture Combinu · Aug 28, 2013 · Viewed 15.6k times · Source

I am using C# to communicate via modbus rs485 rs232 to 2 phase meters that among other log the power voltage.

I have to send data over the bus so that i can receive the readings.
I have connected a normal wire and shorted the send and receive.

The data is recieved and this event is fired:

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    SerialPort sp = (SerialPort)sender;
    byte[] buff = new byte[sp.BytesToRead];

    //Read the Serial Buffer
    sp.Read(buff, 0, buff.Length);
    string data= sp.ReadExisting();

    foreach (byte b in buff)
    {
        AddBuffer(b); //Add byte to buffer
    }
}

Then this buffer is sent to another function which is this one:

private void AddBuffer(byte b)
{
    buffer.Add(b);

    byte[] msg =  buffer.ToArray();

    //Make sure that the message integrity is correct
    if (this.CheckDataIntegrity(msg))
    {
        if (DataReceived != null)
        {
            ModbusEventArgs args = new ModbusEventArgs();
            GetValue(msg, args);
            DataReceived(this, args);
        }
        buffer.RemoveRange(0, buffer.Count);

    }
}

I think that the problem lies at the data integrity check:

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

There is a CRC check and what is strange is that it never becomes true. The CRC calculation:

private void GetCRC(byte[] message, ref byte[] CRC)
{

    ushort CRCFull = 0xFFFF;
    byte CRCHigh = 0xFF, CRCLow = 0xFF;
    char CRCLSB;

    for (int i = 0; i < (message.Length) - 2; i++)
    {
        CRCFull = (ushort)(CRCFull ^ message[i]);

        for (int j = 0; j < 8; j++)
        {
            CRCLSB = (char)(CRCFull & 0x0001);
            CRCFull = (ushort)((CRCFull >> 1) & 0x7FFF);

            if (CRCLSB == 1)
                CRCFull = (ushort)(CRCFull ^ 0xA001);
        }
    }
    CRC[1] = CRCHigh = (byte)((CRCFull >> 8) & 0xFF);
    CRC[0] = CRCLow = (byte)(CRCFull & 0xFF);
}

Answer

Combinu picture Combinu · Sep 5, 2013

The problem is the use of ReadExisting(). It was not to be used in that manner as the buffer was being filled with useless data from the serial port. This problem was identified by @glace in the comments!