SerialPort Class issues

半世苍凉 提交于 2019-12-17 20:08:30

问题


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


回答1:


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.




回答2:


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.



来源:https://stackoverflow.com/questions/21142647/serialport-class-issues

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