Mark
Mark

Reputation: 13

Reading byte value 26 in SerialPort vb.net

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

Answers (1)

Hans Passant
Hans Passant

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

Related Questions