Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read serial port communication into buffer and parse out complete messages

I am using the following code to read values from a com port:

Private port As New SerialPort("COM13", 9600, Parity.None, 8, StopBits.One)

Private Sub port_DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs)
    Debug.Print(port.ReadExisting())
End Sub

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    AddHandler port.DataReceived, New SerialDataReceivedEventHandler(AddressOf port_DataReceived)
    port.Open()
End Sub

This works just fine, but every now and then it doesnt get all the data and in return results in two strings instead of just one.

An example would be if the com port was sending over the word "HELLO2YOU" it was look like:

HEL
LO2YOU

or

HELLO2
YOU

How can i place a buffer in there so that it makes sure it has all the data read before displaying it?

Thanks!

like image 995
StealthRT Avatar asked Jul 12 '12 19:07

StealthRT


People also ask

How do you read a serial port?

In Serial Port Reader go to the “Main menu”, choose “Session -> New session”. Alternately, you can click on the “New” icon on the main toolbar or press “Ctrl + N”. This invokes the “New monitoring session” screen. Terminal view – all received data is displayed in ASCII characters on a text console.

What is serial communication buffer?

The input buffer is computer memory allocated by the serial port object to store data that is to be read from the device. When reading data from your device, the data flow follows these two steps: The data read from the device is stored in the input buffer.

Can you read and write from the same serial port?

Reading and writing to the serial port "at the same time" from different threads is a standard way to handle serial port communications: one thread handles reading, and one handles writing. Acceptable.

What is serial receive buffer?

When serial data enters the device through the DIN pin (or the MOSI pin), it stores the data in the serial receive buffer until the device can process it. Under certain conditions, the device may not be able to process data in the serial receive buffer immediately.


1 Answers

You have to think of Serial Port communications as streaming data. Any time you receive data, you have to expect that it may be a complete message, only a partial message, or multiple messages. It all depends how fast the data is coming in and how fast you application is able to read from the queue. Therefore, you are right in thinking you need a buffer. However, what you may not be realizing yet, is that there is no way to know, strictly via, the Serial Port, where each message begins and ends. That has to be handled via some agreed upon protocol between the sender and the receiver. For instance, many people use the standard start-of-text (STX) and end-of-text (ETX) characters to indicate the beginning and ending of each message send. That way, when you receive the data, you can tell when you have received a complete message.

For instance, if you used STX and ETX characters, you could make a class like this:

Public Class DataBuffer
    Private ReadOnly _startOfText As String = ASCII.GetChars(New Byte() {2})
    Private ReadOnly _endOfText As String = ASCII.GetChars(New Byte() {4})

    Public Event MessageReceived(ByVal message As String)
    Public Event DataIgnored(ByVal text As String)

    Private _buffer As StringBuilder = New StringBuilder

    Public Sub AppendText(ByVal text As String)
        _buffer.Append(text)
        While processBuffer(_buffer)
        End While
    End Sub

    Private Function processBuffer(ByVal buffer As StringBuilder) As Boolean
        Dim foundSomethingToProcess As Boolean = False
        Dim current As String = buffer.ToString()
        Dim stxPosition As Integer = current.IndexOf(_startOfText)
        Dim etxPosition As Integer = current.IndexOf(_endOfText)
        If (stxPosition >= 0) And (etxPosition >= 0) And (etxPosition > stxPosition) Then
            Dim messageText As String = current.Substring(0, etxPosition + 1)
            buffer.Remove(0, messageText.Length)
            If stxPosition > 0 Then
                RaiseEvent DataIgnored(messageText.Substring(0, stxPosition))
                messageText = messageText.Substring(stxPosition)
            End If
            RaiseEvent MessageReceived(messageText)
            foundSomethingToProcess = True
        ElseIf (stxPosition = -1) And (current.Length <> 0) Then
            buffer.Remove(0, current.Length)
            RaiseEvent DataIgnored(current)
            foundSomethingToProcess = True
        End If
        Return foundSomethingToProcess
    End Function


    Public Sub Flush()
        If _buffer.Length <> 0 Then
            RaiseEvent DataIgnored(_buffer.ToString())
        End If
    End Sub
End Class

I should also mention that, in communication protocols, it is typical to have a checksum byte by which you can determine if the message got corrupted during its transmission between the sender and the receiver.

like image 188
Steven Doggart Avatar answered Nov 10 '22 14:11

Steven Doggart