locked
SerialPort DataReceived buffer Construction RRS feed

  • Question

  • Hello

    I've managed to make an application at home using a serialport emulator and connector that will read text from a file on my desktop send it to com1 and then my connector program will merge com1 with com2. In short my program works at home but when I connect it to my device it appears the data in DataReceived is a fraction of what my simulator setup at home is producing, which apparently is completely normal according to all these threads I've read here. 

     

    So I need some assistance with the whole fill my buffer until a certain point and then parse it.

     

    I know exactly how I want to parse it, since the data is in XML I've managed to do all the parsing setup using XML Literals syntax. Since I was using a perfect setup at home and getting a perfect string in I didn't realize that my device would act differently, O well after about 3 weeks of wondering what was wrong with my program that's when I started stumbling over articles on here pointing me to where I need to build up a buffer from my DataReceived event and then pass it to my parsing system. 

    I've seen a few examples on here filling a buffer up to a certain size or length, but I think what I need is a way to concatenate or append all the chucks received until a certain point, pass it to my parser, clear my buffer, and start over again. Gezzz I can state my own solution I just can't code it, damn : /.

     

    Some specifics on my device: 

    The data coming out of my device is all in XML

    The device sends data out continuously and when polled with a specific command "I'm just concerned with continuously right now"

     

    I would like to build up my buffer until the closing tag on my XML "</li840>" is received and then send the string to my parsing system.

     

    Thank you for any assistance 


    Martin Murray
    Wednesday, June 15, 2011 4:34 AM

Answers

  • A queue is a useful device for getting data from the data received event.  But your buffer might be nothing more than a string variable that you keep appending to.  A simple serial port text receiving procedure that uses a textbox text property as the buffer would look like this:

    Add a timer to the form and set the interval to 1000. Declare and initialise a queue object at the form level.

     Dim Q As Queue(Of String) = New Queue(Of String)

    In the data received event, add any data to the queue -

     Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, _
                      ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) _
                      Handles SerialPort1.DataReceived
       Q.Enqueue(SerialPort1.ReadExisting())
     End Sub

    - and in the timer tick event, dequeue any items on the queue, and add them to the text box text. The dequeueing can be enclosed in a sync lock to avoid any possibility of threading issues.

     Private Sub Timer1_Tick(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles Timer1.Tick
      SyncLock Q
      While Q.Count > 0
       txtReceived.Text &= Q.Dequeue
      End While
      End SyncLock
     End Sub

    You could use the string EndsWith method to determine when the buffer has been filled.

    • Marked as answer by Liliane Teng Tuesday, June 21, 2011 6:39 AM
    Wednesday, June 15, 2011 6:19 AM
  • Don't try to do that in the data received event. You will get badly tangled up in knots trying to work out where in your processing you are at.

    Use the data received event to append to your buffer as per the original description.

    Examine the buffer periodically (for instance, in a timer tick event) to determine whether or not enough characters have been received to process it.  For instance, you could examine the buffer to search for a "<li840>" and if you find it then discard every thing in the buffer that occurs before that  Then, examine the buffer to see if it starts with "<li840>" and contains "/<li840>".  If it does, then extract and process the data between those points in the buffer, trim the buffer to the next character after the "/<li840>".   If no processing is required, leave the buffer as is.

    The point is, that the appending to the buffer from the serial data received event proceeds at its own pace as data is received, for all received data, without any processing.  Examining the buffer, extracting data and processing it proceeds as as eeparate activity.

    • Marked as answer by Liliane Teng Tuesday, June 21, 2011 6:38 AM
    Friday, June 17, 2011 9:57 PM

All replies

  • A queue is a useful device for getting data from the data received event.  But your buffer might be nothing more than a string variable that you keep appending to.  A simple serial port text receiving procedure that uses a textbox text property as the buffer would look like this:

    Add a timer to the form and set the interval to 1000. Declare and initialise a queue object at the form level.

     Dim Q As Queue(Of String) = New Queue(Of String)

    In the data received event, add any data to the queue -

     Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, _
                      ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) _
                      Handles SerialPort1.DataReceived
       Q.Enqueue(SerialPort1.ReadExisting())
     End Sub

    - and in the timer tick event, dequeue any items on the queue, and add them to the text box text. The dequeueing can be enclosed in a sync lock to avoid any possibility of threading issues.

     Private Sub Timer1_Tick(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles Timer1.Tick
      SyncLock Q
      While Q.Count > 0
       txtReceived.Text &= Q.Dequeue
      End While
      End SyncLock
     End Sub

    You could use the string EndsWith method to determine when the buffer has been filled.

    • Marked as answer by Liliane Teng Tuesday, June 21, 2011 6:39 AM
    Wednesday, June 15, 2011 6:19 AM
  • Add a SerialPort, a dock fill multiline textbox and a timer to a new Windows Forms Application.
    Replace the code on Form1 with:

    Imports System.IO.Ports
    Public Class Form1
      
    Delegate Sub AddText(ByVal Txt As String)
      
    Sub SerialPort1_DataReceived(ByVal sender As Object, _
                                   
    ByVal e As SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
        TextBox1.Invoke(
    New AddText(AddressOf TextBox1.AppendText), SerialPort1.ReadExisting)
      
    End Sub
      Private Sub Form1_Load(ByVal sender As Object, _
                             
    ByVal e As EventArgs) Handles Me.Load
        SerialPort1.Open()
      
    End Sub
      Private Sub Form1_FormClosing(ByVal sender As Object, _
                                    
    ByVal e As FormClosingEventArgs) Handles Me.FormClosing
        
    If SerialPort1.IsOpen Then
          e.Cancel = True
          Timer1.Start()
        
    End If
      End Sub
      Private Sub Timer1_Tick(ByVal sender As Object, _
                              
    ByVal e As EventArgs) Handles Timer1.Tick
        SerialPort1.Close()
        
    Me.Close()
      
    End Sub
    End
     Class


    Wednesday, June 15, 2011 7:43 AM
  • Hi Acmar, 

     

    I understand what you wrote, in fact I've seen this exact post on other sites, I'm trying to make my DataReceived event stuff my data into a buffer at a certain substring point "<li840>" and end at another substring point "</li840>" and then send it to my parser code. I've seen things on sites that will go by length but I'm having trouble modifying that idea. 

     

    Thanks for the help, much appreciated


    Martin Murray
    Friday, June 17, 2011 12:21 PM
  • Don't try to do that in the data received event. You will get badly tangled up in knots trying to work out where in your processing you are at.

    Use the data received event to append to your buffer as per the original description.

    Examine the buffer periodically (for instance, in a timer tick event) to determine whether or not enough characters have been received to process it.  For instance, you could examine the buffer to search for a "<li840>" and if you find it then discard every thing in the buffer that occurs before that  Then, examine the buffer to see if it starts with "<li840>" and contains "/<li840>".  If it does, then extract and process the data between those points in the buffer, trim the buffer to the next character after the "/<li840>".   If no processing is required, leave the buffer as is.

    The point is, that the appending to the buffer from the serial data received event proceeds at its own pace as data is received, for all received data, without any processing.  Examining the buffer, extracting data and processing it proceeds as as eeparate activity.

    • Marked as answer by Liliane Teng Tuesday, June 21, 2011 6:38 AM
    Friday, June 17, 2011 9:57 PM