Only one byte is read when reading just now opened SerialPort

三世轮回 提交于 2019-12-31 03:18:49

问题


Strange issue.

When I read from com-port with SerialPort.Read(), then if data arrive, only one byte is read on the first call, disregards of count parameter and number of bytes available within timeout. All further readings are ok, only very first has problem

Using SerialPort.DiscardInBuffer() or close/open (reopen) com-port will again cause the problem of the first reading.

Here is some code:

var port = new SerialPort();
port.PortName = "com2";
port.BaudRate = 9600;
port.WriteTimeout = 1000;
port.ReadTimeout = 1000;
port.Open();

// ... send some data first

var read = new byte[10];
if (port.Read(read, 0, read.Length) != read.Length)
{
    // always here at first reading no matter what
}

// ... send some data again

if (port.Read(read, 0, read.Length) != read.Length)
{
    // not here anymore (unless error)
}

Issue doesn't appears if specified amount of data is already available to read when Read() is called.


Some explanation.

Read() is synchronous reading. It will return when specified amount of data is received or timeout is expired. As it seems, TimeoutException will be only thrown if zero bytes are received. If timeout is expired before requested amount of data is read, function will return number of bytes read. Thus, return value has to be compared to requested to see if reading was ok.

But very first call has a problem:

If 0 bytes has arrived during timeout, then first call correctly waits for timeout and trigger TimeoutException. If at least 1 byte has arrived, then function immediately ends, ignoring timeout and requested number of bytes to read altogether.

This is how I see it. Am I wrong? What should I do?


Some more tests. Inserting Thread.Sleep() to ensure that when Read() is called, there will be all data available, will make problem to disappears.

Logically, let's add sleep for only first call. Yay. What???? The problem now appears with second call and only second call. In other word problem appears with the first Read() what will not have all data available but only once.


回答1:


Because at the moment of reading, the other bytes didn't arrive, it will read only one byte because only one is there in the queue. So if at least one byte is there it won't wait for the required number of bytes since timeout has happened but it won't throw and exception. If none is there it will throw timeout exception. Therefore you should try reading until you read as many bytes as you need (10 in your case). You can try with something like this:

int count = 0;
var read = new byte[10];
while ((count += port.Read(read, count, read.Length - count)) != read.Length) ;

but what if timeout happens, maybe this can strengthen the code:

int count = 0;
var read = new byte[10];
while (count < read.Length)
{
    try
    {
        count += port.Read(read, count, read.Length - count);
    }
    catch (TimeoutException te)
    {
        //maybe increase ReadTimeout or something, use exponential backoff, your call
    }
}



回答2:


There are several ways to handle this problem. If you are expecting a reply from a command you send you should sleep for at least 250 msec after calling the serialPort.Write() Before calling serilPort.Read(). Or if you know how many bytes your device is sending back to you can use the serialPort.BytesToRead property to delay reading until the number of bytes you expect are available. If you are using the DataReceived Event you can set the serialPort.ReceivedBytesThreshold (default is 1) to prevent the event from being raised until the expected number of bytes are available. Keep in mind that the serialPort.Read method is not guaranteed to return the number of bytes requested. That is why the serialPort.Read method returns an integer which is the actual number of bytes read.




回答3:


I've found my solution I hpe this helps:

ireadCount = serialPort.Read(readBuffer, 0, serialPort.ReadBufferSize);
Thread.Sleep(1);//This can be removed, just use it in case need time to complete the reception.
ireadCount = serialPort.Read(readBuffer, 1, serialPort.ReadBufferSize-1);
ireadCount +=1;

This way I can have the whole response from the external device without losing the first byte.

Regards.-



来源:https://stackoverflow.com/questions/24676317/only-one-byte-is-read-when-reading-just-now-opened-serialport

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!