1

When using Microsoft Visual Studio with .NET code, there are multiple ways to read data from serial ports, mainly these:

Read

SerialPort.Read(byte[] buffer, int offset, int count);

This reads until the defined buffer is full

Read Existing

SerialPort.ReadExisting();

This reads the currently existing data bytes at the serial Port

Read To

SerialPort.ReadTo(string delimter);

This reads until a defined delimiter, e.g. "\r" is found.

Problem

The issue I am currently facing, is that my device operates in two modes, in normal mode, I can send command, and a response with \n in the end is sent, so this function can be processed with

string response = SerialPort.ReadTo("\n");

In data sending mode, the device sends data in bytes and variable package sizes, the data packets can be 5 to 1024 byte, and have no unique character at the end. In fact, the last characters are a checksum, so they will surely differ in each packet/stream. Therefore, the function

SerialPort.Read(byte[] buffer, int offset, int count);

cannot be used, since count is unknown. Additionally, the function

SerialPort.ReadExisting();

Is of no use, since it will only read the first bytes of the packed, and not the complete data stream.

Workaround

My current workaround is the following, which has the issue that its slow, and relies on the estimation of the highest packet size of 1024. To be

private void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
    Task.Delay(900).Wait()  //9600baud = 1200byte/s = 1024byte/1200byte = 0.85
    string response = SerialPort.readExisting();
}

The major issue with my workaround is that it has to wait the complete time, even if the device sends a small amount of bytes (e.g. 100). Additionally, if the device is switched to a higher speed (e.g. 38400baud) the wait time could be way lower.

How could I deal with this problem in a proper way?

dialer
  • 4,348
  • 6
  • 33
  • 56
snx
  • 33
  • 6
  • You could make it so that you first send a predefined packet size, which you can then use in combination with `SerialPort.Read(byte[] buffer, int offset, int count);`. You could also use `while (port.BytesToRead > 0)` and break out the while loop when a certain end-byte is received. – Leander Feb 14 '21 at 15:29
  • I cannot send packet size. I'm interfacing with a device thats no build of mine, so i have to work with what it has. I cannot customize the device. – snx Feb 14 '21 at 15:55
  • 1
    Are you sure that the response from the device does not contain a fixed-length header at the start, which contains the number of bytes in the packet? That is how it usually works. If not, then the protocol is botched and you're pretty much stuck with an arbitrary delay. – dialer Feb 14 '21 at 16:06
  • These articles may be helpful. [Binary communications protocol parser design for serial data](https://stackoverflow.com/q/3278227/9014308), [C# Wait until data received and go to next iteration](https://stackoverflow.com/q/41334141/9014308), [Fast approach to read and parse serial-data continuously](https://stackoverflow.com/q/31244502/9014308) In any case, you need to be aware of the communication protocol used and process according to it. – kunif Feb 14 '21 at 22:45
  • @dialer the records are shaped like this [#Bllcc?111122223333....s] where LL is the record length, cc is the starting data pointer (not relevant for the serial read), 1111,2222,3333 are the uint32t values in the packet, and s is the checksum. ll can be any from 5 to 1024, and does not count the values before the first value (1111) – snx Feb 15 '21 at 21:32
  • Then I don't understand your problem. First you read bytes up to and including `LL`. Then you look at `LL` and decide how many bytes to read next. – dialer Feb 15 '21 at 21:45

0 Answers0