Reputation: 13
I have an vb.net winforms application that reads/writes serial data to several devices connected to a USB-RS485 device. The application is written in visual basic .NET 2008, altough i tried .NET 2015 as well.
Almost everything is working well except when one of the devices sends a message with a byte value of 26. Then im not sure what exactly happens but after the byte value of 26 the reading seems to stop. And all data after that is read in the next DataReceived event.
I have made a short program to only test the serialport. And it shows exactly the same. Also i have only one device connected with the test. The data the device is sending consists of 10 bytes. The values are 251,20,(6 data bytes),checksum lo, checksum hi.
The first two and last two bytes can never reach a value of 26, it is just the data bytes that can do that.
Imports:
Imports System.IO.Ports
Imports System.Text
Variables:
Dim WithEvents SP_TestCom As SerialPort
Public DataArray() As Byte
subs:
Public Sub OpenCom()
If SP_TestCom.IsOpen Then
Exit Sub
End If
SP_TestCom.Open()
End Sub
Public Sub CloseCom()
If Not SP_TestCom.IsOpen Then
Exit Sub
End If
SP_TestCom.Close()
End Sub
Public Sub SendData(ByVal Data() As Byte)
Try
If SP_TestCom.IsOpen Then
SP_TestCom.Write(Data, 0, Data.Length)
End If
Catch ex As Exception
End Try
End Sub
Private Sub SP_TestCom_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SP_TestCom.DataReceived
Try
If SP_TestCom.BytesToRead > 0 Then
Dim DataArray_Temp(SP_TestCom.BytesToRead + 1) As Byte
SP_TestCom.Read(DataArray_Temp, 0, SP_TestCom.BytesToRead)
Array.Copy(DataArray_Temp, DataArray, DataArray_Temp.Length)
End If
Catch ex As Exception
End Try
End Sub
I have a main form with two buttons and a timer. The buttons are for opening and closing the port. The timer reads the dataarray
I have tried several ways of reading.
I also tried different encodings. Although i am not sure if it would have any effect.
All gives the same error.
I could bypass the error by ignoring any message containing a byte value of 26. This at least does not give me strange results in the rest of my application but it is not the perfect solution.
Does anyone have an idea of what the issue might be?
Edit:
Public Sub InitSerial()
SP_TestCom = New SerialPort
SP_TestCom.PortName = "COM26"
SP_TestCom.ReadTimeout = 20
SP_TestCom.BaudRate = 19200
SP_TestCom.DataBits = 8
SP_TestCom.StopBits = StopBits.One
SP_TestCom.Parity = Parity.None
SP_TestCom.ReceivedBytesThreshold = 10
End Sub
Upvotes: 1
Views: 1558
Reputation: 941277
SP_TestCom.ReceivedBytesThreshold = 10
That is a fairly troublesome property. Yes, 26 is a magic number. It is Ctrl+Z, the default end-of-file character. Dates back to the stone age, unfortunately it cannot be changed.
It matters to your DataReceived event handler, it will fire one extra time to tell you about Eof. That screws up your logic, the value of BytesToRead is unpredictable. You have to get out quickly, like this:
Private Sub SP_TestCom_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SP_TestCom.DataReceived
If e.EventType <> SerialData.Chars Then Return
'' etc...
End Sub
Not the only problem with that property. You now have a guarantee that ReceivedBytes will be at least 10. Make sure you actually pass 10 to the Read() method. But you don't know which 10 you'll get. It could for example be 4 bytes of the previous packet and 6 bytes of the next. That is not going to work well unless you very carefully control the start-up order. The device must be turned on after your program starts up so you have a hard guarantee that the first byte you receive is the first byte of a packet. Could work if you must send an explicit command to the device to start sending.
Or you may need to detect the start of a packet by a special byte value, like 251 in your case. You then synchronize by reading single bytes, throwing ones away until you get 251. You can't do that with ReceivedBytesThreshold > 1.
Also very, very important to use the ErrorReceived event. Overrun errors happen, especially when there is no handshaking, you must re-synchronize when they occur.
You also need to pay attention to how you process the packet. If you cannot do so in the DataReceived event handler then you need a thread-safe queue to ensure no data is lost.
Upvotes: 4