Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SerialPort Class issues

Tags:

c#

serial-port

I am having a lot of issues trying to get a serial port to receive the correct message. It keeps truncating the messages. Here is my code and I will try to elaborate after the code.

public SerialComms(SerialPort sp)
{
   this.sp = sp;
   this.sp.Open();
   this.sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);

   do
   {
      Console.WriteLine("port open waiting message");
      Console.ReadKey();
   } while(!_terminate);

   this.sp.Close();
}

void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
   string dataReceived;
   StringComparer strComp = StringComparer.OrdinalIgnoreCase;
   SerialPort sp = (SerialPort)sender;
   int i = sp.BytesToRead;
   byte[] _byte = new byte[i];
   char[] _char = new char[i];
   sp.read(_byte, 0, i);
   dataReceived = Encoding.UTF8.GetString(_byte);
   //dataReceived = new string(_char);
   //dataReceived = sp.ReadExisting();

   if (strComp.Equals("00000000000000"), dataReceived))
      _terminate = true;

   Console.WriteLine(dataReceived);
}

Now I have a test project that we use for testing our serial coms in production with legacy software- I know this runs fine. I have attached a serial monitor to the port and the message coming through transmits without any issues. When I send a message such as 012345678901234 the first time through it usually goes through just fine, and on the receiving end, the monitor shows it coming through; however, when it prints to the console it gets truncated after the first message. I am attaching screenshots of the message going through on the port monitor and the console output (the smiley face and heart that show up are the prefix bytes being converted- why it is a heart and a smiley face I have no idea)

Ok so I can't post the image because of the fact that I do not have enough reputation to do so. I will write what the output looks like to the console below (in this case for some reason it truncated the first message as well :( )

On the serial port monitor the message being transmitted is as follows (I sent it three times with a few seconds 'lag time' between each message send):
02 31 32 33 34 35 36 37 38 39 30 31 32 33 34 03 .12345678901234.
02 31 32 33 34 35 36 37 38 39 30 31 32 33 34 03 .12345678901234.
02 31 32 33 34 35 36 37 38 39 30 31 32 33 34 03 .12345678901234.

On the console I received the following (The ☺ and ♥ characters are 02 and 03, they are an STX and ETX message that is standard for our transmissions):
☺123456
78901234♥

123
456
7890
123
4♥

123
456
7890
123
4♥

This issue is driving me mad!!! Please help! The legacy is using the outdated MSCommLib and we are moving to .Net 4

like image 509
Nyra Avatar asked Jan 15 '14 16:01

Nyra


People also ask

What are different issues behind serial communication?

The most common cause of serial port communication problems is incorrect communication parameter settings. To operate correctly it is essential that both devices are set up with the same communication parameters, which includes baud rate, parity, number of data bits, and number of stop bits.

How do I fix a serial port problem?

Go to Device Manager > Ports (COM & LPT) > mbed Serial Port, then right-click and select "properties". Choose "Port Settings" Tab, and click "Advanced" Under "COM Port Number", try selecting a different COM port. Unplug and replug the mbed to reload the driver - if the problem persists, try another COM port.

How do I test if a port is working?

To test if the computer COM port is functioning correctly, you can do a simple loopback test. (In a loopback test, a signal is sent from a device and returned, or looped back, to the device.) For this test, connect a serial cable to the COM port that you want to test. Then short pin 2 and pin 3 of the cable together.

What is serial port error?

When printing from a computer and using a serial port, if you get the "Failed to Open Serial Port" error, that usually means that you have two or more serial printers or devices (Palm Pilot, modem, printer, etc.) installed, both using the same COM port.


2 Answers

This is entirely normal and common in any communication protocol. TCP over a network has this property as well. Bytes are transferred as a stream, not a packet of data. So when your DataReceived event handler fires, you only know that you have some bytes available. It is up to you to assemble the receive bytes into a complete response before you process it.

This requires a protocol, a way to recognize that you got a full response. You have one, those STX and ETX bytes tell you. ETX in particular, the STX is a way to filter out noise bytes that you might get when you connect the device.

A very simple way to get it going is to set the NewLine property to (char)3 and just call ReadLine().

A better way to do this is to also filter the noise that STX helps you to eliminate, also avoids a deadlock scenario:

private const int MaxResponse = 42;
private const int STX = 2;
private const int ETX = 3;
private byte[MaxResponse] response;
private int responseLength;

void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
   var sp = (SerialPort)sender;
   int cnt = sp.BytesToReceive;
   for (int ix = 0; ix < cnt; ++ix) {
       byte b = (byte)sp.ReadByte();
       if (responseLength == 0 && b != STX) continue;
       if (b != ETX) response[responseLength++] = b;
       else {
           var str = Encoding.ASCII.GetString(response, 0, responseLength);
           HandleResponse(str);
           responseLength = 0;
       }
   }
}

And write the HandleResponse() method to process the data you received.

like image 54
Hans Passant Avatar answered Sep 21 '22 00:09

Hans Passant


There is a possible combination of two issues.

First, a common mistake when working with streams is that just because you request i bytes from Read does not mean that Read will actually read that many bytes, it is not likely your problem but you should be aware of it, see this question's answer for the proper pattern.

Second issue is streams are streams, not messages. It does not know that you sent ☺12345678901234♥, it just knows that it received ☺123456 between the last time it checked and now and it should report that information to the user.

You need to modify your reading code to keep buffering the data till it receives the next then take that entire buffered byte array and send it to the user. That is the entire reason for the and being sent along the wire, it allows the receiver to be able to detect when it has hit the begin or end of a message.

like image 38
Scott Chamberlain Avatar answered Sep 22 '22 00:09

Scott Chamberlain