paradox
paradox

Reputation: 1276

C# Serialport not receiving all the bytes in a single transmission

I'm using the following code to receive hex data over the serial port, it seems that some of these transmissions are broken up into 2 lines when they are parts of the same transmission. How do I make sure that each transmission is received properly?

public void Receiver(object sender, SerialDataReceivedEventArgs e)
{
    string data;

    do
    {
        data = COMPort.ReadExisting();
    } while (COMPort.BytesToRead != 0);

    RxARR = data.ToCharArray().ToList();
    Dispatcher.Invoke(new MethodInvoker(Display)); // Start "Display" on the UI thread
} 

Upvotes: 2

Views: 5895

Answers (2)

Thorsten Dittmar
Thorsten Dittmar

Reputation: 56697

You should never assume that data from a serial port is provided to you in one go (the same is true for network communication by the way). You need to make sure that your code accepts a message only if you have received everything.

Everything is hard to define. This can either be all characters until a defined termination sequence (for example \r\n or EOL byte) or until a fixed number of bytes is read. Generally one can say, as every message can be fragmented, reliable communcation is not possible without a defined end of message signal.

What we do is:

  1. Create a StringBuilder
  2. Read everything into that StringBuilder
  3. Search for termination sequence
  4. Remove everything from the StringBuilder up to and including the termination sequence
  5. Process that chunk of data
  6. Repeat from 3 until termination sequence is not found
  7. Keep the remaining characters in StringBuilder, as this is the start of a new message

Pseudo code:

private StringBuilder serialBuffer = new StringBuilder();
private string terminationSequence = "\r\n"; // Anything that can't be part of a message

public void Receiver(object sender, SerialDataReceivedEventArgs e)
{
    string data = COMPort.ReadExisting();
    serialBuffer.Append(data);

    string bufferString = serialBuffer.ToString();

    int index = -1;
    do
    {
        index = bufferString.IndexOf(terminationSequence);  
        if (index > -1)
        {
            string message = bufferString.Substring(0, index);
            bufferString = bufferString.Remove(0, index + terminationSequence.Length);

            HandleMessage(message);
        }
    }
    while (index > -1)

    serialBuffer = new StringBuilder(bufferString);
} 

By the way: Looping within your DataReceived event is not desired, as this event is called by the SerialPort whenever something new is ready to be read. Reading in a loop may interfere with what SerialPort is doing by default. So: Don't read in a loop within that event! The "loop" is the event being fired in sequence by SerialPort.

Upvotes: 8

Pacheco
Pacheco

Reputation: 1030

I Had almost the same situation.

Like Thorsten said the data sometimes does not come at once.. Maybe because of Hardware or BaundRate..

What really works for me was:

        var end = '\r';
        int dataLength = _serialPort.BytesToRead;
        byte[] data = new byte[dataLength];
        int nbrDataRead = _serialPort.Read(data, 0, dataLength);

        RxString = Encoding.ASCII.GetString(data);
        txtCod.AppendText(RxString);

        if (RxString.IndexOf((char)end) > -1)
        {
            this.Invoke(new EventHandler(Final));   
        } 

Upvotes: 0

Related Questions