.NET SerialPort.Read skipps bytes
- by Lukas Rieger
Solution
Reading the data byte wise via "port.ReadByte" is too slow, the problem is inside the SerialPort class.
i changed it to reading bigger chunks via "port.Read" and there are now no buffer overruns.
although i found the solution myself, writing it down helped me and maybe someone else has the same problem and finds this via google...
(how can i mark it as answered?)
EDIT 2
by setting
port.ReadBufferSize = 2000000;
i can delay the problem for ~30 seconds. so it seems, .Net really is too slow...
since my application is not that critical, i just set the buffer to 20MB, but i am still interested in the cause.
EDIT
i just tested something i had not thought of before (shame on me):
port.ErrorReceived += (object self, SerialErrorReceivedEventArgs se_arg) => { Console.Write("| Error: {0} | ", System.Enum.GetName(se_arg.EventType.GetType(), se_arg.EventType)); };
and it seems that i have an overrun. Is the .Net implementation too slow for 500k or is there an error on my side?
Original Question
i built a very primitive oszilloscope (avr, which sends adc data over uart to an ftdi chip). On the pc side i have a WPF Programm that displays this data.
The Protokoll is:
two sync bytes (0xaffe) - 14 data bytes - two sync bytes - 14 data bytes - ...
i use 16bit values, so inside the 14 data bytes are 7 channels (lsb first).
I verified the uC Firmware with hTerm, and it does send and receive everything correct.
But, if i try to read the data with C#, sometimes some bytes are lost.
The oszilloscop programm is a mess, but i created a small sample application, which has the same symptoms.
I added two extension methods to a) read one byte from the COM Port and ignore -1 (EOF)
and b) wait for the sync pattern.
The sample programm first syncs onto the data stream by waiting for (0xaffe) and then compares the received bytes with the expected values. the loop runs a few times until an assert failed message pops up.
I could not find anything about lost bytes via google, any help would be appreciated.
Code
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SerialTest
{
public static class SerialPortExtensions
{
public static byte ReadByteSerial(this SerialPort port)
{
int i = 0;
do
{
i = port.ReadByte();
} while (i < 0 || i > 0xff);
return (byte)i;
}
public static void WaitForPattern_Ushort(this SerialPort port, ushort pattern)
{
byte hi = 0;
byte lo = 0;
do
{
lo = hi;
hi = port.ReadByteSerial();
} while (!(hi == (pattern >> 8) && lo == (pattern & 0x00ff)));
}
}
class Program
{
static void Main(string[] args)
{
//500000 8n1
SerialPort port = new SerialPort("COM3", 500000, Parity.None, 8, StopBits.One);
port.Open();
port.DiscardInBuffer();
port.DiscardOutBuffer();
//Sync
port.WaitForPattern_Ushort(0xaffe);
byte hi = 0;
byte lo = 0;
int val;
int n = 0;
// Start Loop, the stream is already synced
while (true)
{
//Read 7 16-bit values (=14 Bytes)
for (int i = 0; i < 7; i++)
{
lo = port.ReadByteSerial();
hi = port.ReadByteSerial();
val = ((hi << 8) | lo);
Debug.Assert(val != 0xaffe);
}
//Read two sync bytes
lo = port.ReadByteSerial();
hi = port.ReadByteSerial();
val = ((hi << 8) | lo);
Debug.Assert(val == 0xaffe);
n++;
}
}
}
}