0

I'm reading serial port. But one of the response is bigger than 127, let's say the length can up to 4,294,967,295. As current I'm facing, the data length is 250(this value is dynamic).

The data currently arrived in partial. It comes on first 100, and then it comes next. The length of the response is lies on the buffer itself.

Currently, this is how I read response from serial port.

List<byte> serialByte = new List<byte>();
int bufferLen = 0;
void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    if (this.InvokeRequired)
    {
        this.Invoke(new SerialDataReceivedDelegate(SerialPort_DataReceived_Client), sender, e);
    }
    else
    {
        SerialPort_DataReceived_Client(sender, e);
    }
}
void SerialPort_DataReceived_Client(object sender, SerialDataReceivedEventArgs e)
{
    SerialPort sp = (SerialPort)sender;
    if (!sp.IsOpen) return;
    var buffer = (dynamic)null;
    bool newData = true;
    int BytesToRead = sp.BytesToRead;
    AppendTextBox($"BytesToRead: {BytesToRead}");
    byte[] temp = new byte[BytesToRead];
    sp.Read(temp, 0, BytesToRead);

    bufferLen = TLV.GetExpectedLength(temp);
    AppendTextBox($"Buffer Len: {bufferLen}");

    bool waitFullData = true;
    bool isLenRetrieved = false;
    serialByte.AddRange(temp);
    buffer = new byte[bufferLen];
    buffer = serialByte.ToArray();
    DataReceived_TranslateData(buffer);
}

Log:-

Sample content length is below 127

15:09:32.351167 PM - BytesToRead: 40
15:09:32.361139 PM - Expected Length: 40

Sample content length is above 127

15:10:12.783806 PM - BytesToRead: 100
15:10:12.815695 PM - Buffer Len: 271

If the bufferLen is equal to serialByte.Count, the data is complete and I will pass the byte[] to method DataReceived_TranslateData.

I'm try to perform as below but, my UI freeze which I know that my way is totally wrong.

List<byte> serialByte = new List<byte>();
int bufferLen = 0;
bool waitFullData = true;
bool isLenRetrieved = false;
void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    if (this.InvokeRequired)
    {
        this.Invoke(new SerialDataReceivedDelegate(SerialPort_DataReceived_Client), sender, e);
    }
    else
    {
        SerialPort_DataReceived_Client(sender, e);
    }
}
void SerialPort_DataReceived_Client(object sender, SerialDataReceivedEventArgs e)
{
    SerialPort sp = (SerialPort)sender;
    if (!sp.IsOpen) return;
    var buffer = (dynamic)null;
    bool newData = true;
    int BytesToRead = sp.BytesToRead;
    AppendTextBox($"BytesToRead: {BytesToRead}");
    byte[] temp = new byte[BytesToRead];
    sp.Read(temp, 0, BytesToRead);

    bufferLen = TLV.GetExpectedLength(temp);
    AppendTextBox($"Buffer Len: {bufferLen}");

    while (waitFullData)
    {
        if (!isLenRetrieved)
        {
            bufferLen = TLV.GetExpectedLength(temp);
            isLenRetrieved = true;
            AppendTextBox($"Buffer Len: {bufferLen}");
        }
        if (newData)
        {
            serialByte.AddRange(temp);
            newData = false;
        }

        if (bufferLen == serialByte.Count)
        {
            waitFullData = false;
            break;
        }
        else
        {
            Thread.Sleep(100);
        }
    }
    buffer = new byte[bufferLen];
    buffer = serialByte.ToArray();
    DataReceived_TranslateData(buffer);
}

How to wait for next serial port data until the length is match with expected length?

Luiey
  • 843
  • 2
  • 23
  • 50
  • UI freezes because you invoke a complete method, including waiting (blocking) loop. Consider to only invoke parts which need to be invoked (probably only `AppendTextBox()` needs it, but you may also need some `lock` for arrays or change their type to something accomodating concurrency). – Sinatr Jul 17 '20 at 07:30

1 Answers1

2

First, don't use this.Invoke to call the whole method, just put UI update code in it, like your AppendTextBox method.

Second, do not WAIT in the DataReceived event. Because this event is triggered every time the serial port gets data. The while loop just blocks it.

Your code should be like this:

    List<byte> serialByte = new List<byte>();
    int bufferLen = 0;

    private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        SerialPort sp = (SerialPort)sender;
        if (!sp.IsOpen) return;

        //other codes

        int BytesToRead = sp.BytesToRead;
        byte[] temp = new byte[BytesToRead];
        sp.Read(temp, 0, BytesToRead);

        serialByte.AddRange(temp);

        //other codes

        if (serialByte.Count >= bufferLen)
        {
            DataReceived_TranslateData(serialByte.GetRange(0, bufferLen).ToArray());
            //clear the list if you need
        }
    }
逍遥子k
  • 177
  • 5
  • This did it, log that I have: `1. BytesToRead Len: 100, 2. Expected Content Len: 271, 3. BytesToRead Len: 171`. On parsing the byte, I got `Full Len: 271, Child Len: 265` and the data extract perfectly. – Luiey Jul 17 '20 at 08:21