Results 1 to 28 of 28

Thread: [RESOLVED] How to Handle Serial data event and new frame event using Aforge library at same time

  1. #1

    Thread Starter
    Member
    Join Date
    Jan 2018
    Posts
    39

    Resolved [RESOLVED] How to Handle Serial data event and new frame event using Aforge library at same time

    hello everyone,

    I'm using AFORGE video library in my project for video capturing. Also, I'm using serial data receive event for capturing incoming serial data.

    My issue is that when I run both together then my project hangs and video capture get's very slow.

    Do I need to use Video capture in another thread ? The video new frame event fires whenever there is a new frame from the camera and record the video.

    below is my code regarding the problem.

    Code:
    Imports AForge.Video
    Imports AForge.Video.DirectShow
    Imports Accord.Video.FFMPEG
    
     Dim CAMERA As VideoCaptureDevice
        Dim BMP As Bitmap
        Dim VIDEOFRAME As Bitmap
        Dim RECORDER As New VideoFileWriter()
        Dim LOADER As New VideoFileReader()
        Dim FPS As Integer = 30
        Dim BRT As Integer = 300
    
    Private Sub SerialPort1_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
            
            While SerialPort1.BytesToRead > 0
                        
                datastring = SerialPort1.ReadLine
                datapacket = Integer.Parse(datastring)
               
                Me.BeginInvoke((New MyDelegate(AddressOf DrawGraph2)), datapacket)
    
    
           
            End While
    End Sub
    
    Private Sub DrawGraph2(XVALUE1 As Integer)
     //plot data
    End Sub
    
    Private Sub Video_ToolStripButton_Click(sender As Object, e As EventArgs) Handles Video_ToolStripButton.Click
            If Video_ToolStripButton.Text = "Video Off" Then
               Dim CAMARAS As VideoCaptureDeviceForm = New VideoCaptureDeviceForm()
                If CAMARAS.ShowDialog() = DialogResult.OK Then
                    CAMERA = CAMARAS.VideoDevice
                    AddHandler CAMERA.NewFrame, New NewFrameEventHandler(AddressOf CAPTURER)
                    CAMERA.Start()
                End If
               
                Video_PictureBox.Location = New Point(Panel1.Width - (Video_PictureBox.Width + 10), 5)
               Video_PictureBox.Visible = True
                Video_ToolStripButton.Text = "Video On"
            ElseIf Video_ToolStripButton.Text = "Video On" Then
                Video_ToolStripButton.Text = "Video Off"
                Video_PictureBox.Visible = False
            End If
           
        End Sub
    
    Private Sub CAPTURER(sender As Object, eventArgs As NewFrameEventArgs)
             If Video_ToolStripButton.BackColor = Color.White Then
            BMP = DirectCast(eventArgs.Frame.Clone(), Bitmap)
            
    
            Video_PictureBox.Image = DirectCast(eventArgs.Frame.Clone(), Bitmap)
    
            Else
                Try
                    BMP = DirectCast(eventArgs.Frame.Clone(), Bitmap)
                    Video_PictureBox.Image = DirectCast(eventArgs.Frame.Clone(), Bitmap)
                     RECORDER.WriteVideoFrame(BMP)
                Catch ex As Exception
                End Try
            End If
        End Sub
    kindly help in resolving the issue.

  2. #2
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,754

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    As far as the serial port goes you have it hung up waiting for data. In general it is bad practice to have the DataReceived event handler waiting. In the example below I show an alternative method. You should be able to modify the code after this line, 'process your message here <<<<<<<<<<<<, to handle your situation. Hopefully it helps.

    Code:
        Private ReadSerialPortTask As task
        Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
            'start the worker task <<<<<<<<<<<<!!!!!
            'this could be in the load event also
            ReadSerialPortTask = Task.Run(Sub() ReadSerialPort())
        End Sub
    
        Private Sub SerialPort1_DataReceived(sender As Object,
                                             e As IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
            'this is it
            ReadWait.Set() 'cause ReadSerialPort to run
        End Sub
    
        Private ReadWait As New Threading.AutoResetEvent(False)
        Private Sub ReadSerialPort()
            '
            'this is run as a Background task
            '
            Dim data As New System.Text.StringBuilder(1024 * 1024) 'accumulate SerialPort data here
            Dim mess As New System.Text.StringBuilder 'individual message
            Dim foundMess As Boolean = False
            Do
                ReadWait.WaitOne() 'wait for SerialPort1.DataReceived
    
                Do While SerialPort1.BytesToRead > 0 'accumulate all available bytes
                    data.Append(SerialPort1.ReadExisting)
                Loop
                Do 'process message, if one available
    
                    mess.Length = 0 'reset message
                    foundMess = False 'not found
                    Dim idx As Integer = 0
                    For idx = 0 To data.Length - 1 'look for CR
                        If data(idx) = ControlChars.Cr Then
                            'note that the CR will NOT be in mess
                            foundMess = True 'found message
                            Exit For
                        End If
                        mess.Append(data(idx))
                    Next
                    If foundMess Then
                        data.Remove(0, idx + 1) 'remove found message from data
                        '
                        'process your message here <<<<<<<<<<<<
                        'note how UI interaction is handled in example
                        '
    
                        'example MY message has two parts separated by tab
                        Dim parts() As String
                        parts = mess.ToString.Split(ControlChars.Tab)
                        'how to interact with the UI
                        Me.Invoke(Sub()
                                      Label1.Text = parts(0)
                                      RichTextBox1.AppendText(parts(1))
                                      RichTextBox1.AppendText(ControlChars.Cr)
                                      RichTextBox1.ScrollToCaret()
                                  End Sub)
                        'end example
                    End If
    
                    'look for more messages in data?
                Loop While foundMess AndAlso data.Length > 0
            Loop
        End Sub
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  3. #3

    Thread Starter
    Member
    Join Date
    Jan 2018
    Posts
    39

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    Thanks for your valuable reply.

    But I am not able to use Task because I'm using Dotnet framework 3.5 (Aforge Video Library works only in Dotnet Framework 3.5 and below).

    So, Please provide me alternative for this. I shall be very thankful .

  4. #4

    Thread Starter
    Member
    Join Date
    Jan 2018
    Posts
    39

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    Hi,

    I used TASKPARALLELLIBRARY which is meant for .net framework 3.5. I followed your suggestion and made necessary code changes. below is the code I tried. Im reading data as readline because my incoming data is terminating with a newine.

    Code:
       Private ReadSerialPortTask As task
     Private ReadWait As New Threading.AutoResetEvent(False)
    
     Private Sub Acquire_Load(sender As Object, e As EventArgs) Handles MyBase.Load
          
            Dim monitorWidth As Integer = My.Computer.Screen.WorkingArea.Size.Width
            Dim monitorHeight As Integer = My.Computer.Screen.WorkingArea.Size.Height
            ' --- adjust size of this form ** this does NOT make consideration of DPI (eg. 125%, 150%) **
            Me.Width = monitorWidth
            Me.Height = monitorHeight
            Control.CheckForIllegalCrossThreadCalls = False
            Plotting_Signal = New Bitmap(Panel1.Width, Panel1.Height)
            Dim g As Graphics = Me.CreateGraphics
            Monitor_PPI_On_Y = g.DpiY
            Pixels_Per_MM = Monitor_PPI_On_Y / 25.4
            Sens_factor = SensFunction(7.5)
            SweepFunction(10)
            SerialPort1.PortName = "COM7"
               
          ReadSerialPortTask = Task.Factory.StartNew(Sub() ReadSerialPort())
        End Sub
    
    
        Private Sub ReadSerialPort()
            
            'this is run as a Background task
                  
            Do
                ReadWait.WaitOne() 'wait for SerialPort1.DataReceived
    
                Do While SerialPort1.BytesToRead > 0 'accumulate all available bytes
                  
                   datastring = SerialPort1.ReadLine
                    datapacket = Integer.Parse(datastring)
    
                    Me.BeginInvoke((New MyDelegate(AddressOf DrawGraph2)), datapacket)
                Loop
             
            Loop
        End Sub
    I can still see some hung up in UI response. for example if I click a button , The button event fires a little late after hanging up.

    Iam even recording the video and storing serial data in a binary file. The recorded video & stored data both are OK. It's the UI which has slow response.
    I have started the TASK in Form Load event instead of FORM shown. Does it make any difference?

    looking forward for your reply.

  5. #5
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,754

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    My opinion is that you should do this,

    Code:
        Private ReadSerialPortTask As Task
        'Private ReadSerialPortThread As Threading.Thread
        Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
            'start the worker task <<<<<<<<<<<<!!!!!
            'this could be in the load event also
            ReadSerialPortTask = Task.Factory.StartNew(Sub() ReadSerialPort())
            'ReadSerialPortThread = New Threading.Thread(AddressOf ReadSerialPort)
            'ReadSerialPortThread.IsBackground = True
            'ReadSerialPortThread.Start()
        End Sub
    
        Private Sub SerialPort1_DataReceived(sender As Object,
                                             e As IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
            'this is it
            ReadWait.Set() 'cause ReadSerialPort to run
        End Sub
    
        Private ReadWait As New Threading.AutoResetEvent(False)
        Private Sub ReadSerialPort()
            '
            'this is run as a Background task
            '
            Dim data As New System.Text.StringBuilder(1024 * 1024) 'accumulate SerialPort data here
            Dim mess As New System.Text.StringBuilder 'individual message
            Dim foundMess As Boolean = False
            Do
                ReadWait.WaitOne() 'wait for SerialPort1.DataReceived
    
                Do While SerialPort1.BytesToRead > 0 'accumulate all available bytes
                    data.Append(SerialPort1.ReadExisting)
                Loop
                Do 'process message, if one available
    
                    mess.Length = 0 'reset message
                    foundMess = False 'not found
                    Dim idx As Integer = 0
                    For idx = 0 To data.Length - 1 'look for CR??????
                        If data(idx) = ControlChars.Cr Then '<<<<<<<<<<<<<<<<<<<<<<<
                            'note that the CR will NOT be in mess
                            foundMess = True 'found message
                            Exit For
                        End If
                        mess.Append(data(idx))
                    Next
                    If foundMess Then
                        data.Remove(0, idx + 1) 'remove found message from data
                        '
                        'process your message here <<<<<<<<<<<<
                        '
                        Dim datapacket As Integer
                        If Integer.TryParse(mess.ToString, datapacket) Then
                            Me.Invoke((New MyDelegate(AddressOf DrawGraph2)), datapacket)
                        Else
                            'invalid
                        End If
                    End If
    
                    'look for more messages in data?
                Loop While foundMess AndAlso data.Length > 0
            Loop
        End Sub
    So I tried to help and you decided not to take my advice.

    The problem with the UI might be something else entirely. If you had read the comments one of the questions was answered.
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  6. #6
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    I tend to use the DataReceived event and collecting data and frame parsing, etc... when the data to be read can't be self framing, i.e. you can't use ReadLine.

    If you can use ReadLine, so the messages are self framing, then I use that. I don't have any loop in the event, and I don't use ReadExisting.

    You get an event, you do the ReadLine, you process the line and exit the event. Very straight forward.

    If your processing of the data to do the graphing is hanging up your GUI thread, then you may need to consider not invoking back to the GUI thread to do the bulk of the drawing, or any of the drawing.

    Either do the drawing in a bitmap from the background thread, and then only invoke the Gui thread to update the panel using the bitmap, or take it a step further and create a Buffered Graphics Object and use the panel as it's display surface. That way you can do all the processing and drawing in the background thread using the Buffered Graphics Object's graphic object and refresh the image area of the panel from the background thread. You wouldn't be doing any drawing or updating of the panel from the GUI thread, so no cross-threading issue.

    An example of using the BufferedGraphics object to update the image area of a panel from a background thread.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  7. #7
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,754

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    Quote Originally Posted by passel View Post
    I tend to use the DataReceived event and collecting data and frame parsing, etc... when the data to be read can't be self framing, i.e. you can't use ReadLine.

    If you can use ReadLine, so the messages are self framing, then I use that. I don't have any loop in the event, and I don't use ReadExisting.

    You get an event, you do the ReadLine, you process the line and exit the event. Very straight forward....
    The problem with a self framing message using readline in the DataReceived event handler is that that handler might fire multiple times before a line termination character is received.
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  8. #8
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    Doesn't matter. Each event is raised in a different thread in that case. You wouldn't loose anything since you're reading the buffer from the first event.
    I haven't examined in detail whether you end up with a number of parallel threads with pending ReadLines in them. It seemed to me that you might end up with two, one that is processing the ReadLine, and possibly a second to raise an event for data being received that isn't being handled by the current ReadLine.
    If a Readline is active, I don't think a data received event is generated for new data that is being drained by the Readline. I believe the serial driver is filling the Readline request, and won't raise another event unless it has new data after satisfying the Readline.

    If I only have data that can be processed by Readline, so don't need to switch between Readline and Readexisting, I usually don't even bother with coding an event handler for the DataReceived event.
    I just start a background thread, and have a loop, and let the background thread sit on the Readline call. The serial driver will buffer the data, and return the string to the call on that background thread, I'll process it, and then loopback and suspend on the Readline until the Serial driver returns the next line.

    That is the whole reason Readline exists, to make it easy to process serial data that is framed by lines, letting the thread suspend on the call, and the serial driver buffer the data and return the line to the suspended thread when it has a line. No need for a DataReceived event handler in that scenario.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  9. #9

    Thread Starter
    Member
    Join Date
    Jan 2018
    Posts
    39

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    Hi,

    I tried implementing your suggested code. The UI is running fine now, But due to read existing the data is incomplete at the end of array in which we are appending the serial buffer.
    The incoming serial data is terminating with "\n" But in Read existing mode, It is not necessary that the last byte will be of new line character only. It will simply just dump whatever is in the serial buffer without taking the newline ending criteria.

  10. #10
    Lively Member
    Join Date
    Jul 2017
    Posts
    73

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    If I only have data that can be processed by Readline, so don't need to switch between Readline and Readexisting, I usually don't even bother with coding an event handler for the DataReceived event.
    I just start a background thread, and have a loop, and let the background thread sit on the Readline call. The serial driver will buffer the data, and return the string to the call on that background thread, I'll process it, and then loopback and suspend on the Readline until the Serial driver returns the next line.

    That is the whole reason Readline exists, to make it easy to process serial data that is framed by lines, letting the thread suspend on the call, and the serial driver buffer the data and return the line to the suspended thread when it has a line. No need for a DataReceived event handler in that scenario.

    Can You share an example of this?

  11. #11
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,754

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    Quote Originally Posted by Vinod Chauhan View Post
    Hi,

    I tried implementing your suggested code. The UI is running fine now, But due to read existing the data is incomplete at the end of array in which we are appending the serial buffer.
    The incoming serial data is terminating with "\n" But in Read existing mode, It is not necessary that the last byte will be of new line character only. It will simply just dump whatever is in the serial buffer without taking the newline ending criteria.
    Is the termination character CR or LF? How do you know when you have a complete message?
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  12. #12

    Thread Starter
    Member
    Join Date
    Jan 2018
    Posts
    39

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    Hi,

    I checked my incoming string data. It is like "82763"&vbCrLf&"82507"&vbCrLf &"82769"&vbCrLf.
    The number is the actual data followed by CrLf.

    I tried using If data(idx) = ControlChars.CrLf or ControlChars.Newline ,but it never gets true. It only goes inside If either by checking ControlChars.Cr or ControlChars.Lf

  13. #13
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,754

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    Ignore one terminator
    Code:
    If data(idx) = ControlChars.Cr Then '<<<<<<<<<<<<<<<<<<<<<<<
         'note that the CR will NOT be in mess
         foundMess = True 'found message
          Exit For
    ElseIf data(idx) = ControlChars.LF Then '<<<<<<<<<<<<<<<<<<<<<<<
         Continue For
    End If
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  14. #14

    Thread Starter
    Member
    Join Date
    Jan 2018
    Posts
    39

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    when I used Me.invoke the data doesn't plotted properly..
    but While using Me.BeginInvoke Plotting is ok..

    Please tell me the difference Between Me.Invoke And Me.BeginInvoke.

  15. #15
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,754

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  16. #16
    Junior Member
    Join Date
    Jul 2020
    Posts
    24

    Re: How to Handle Serial data event and new frame event using Aforge library at same


  17. #17

    Thread Starter
    Member
    Join Date
    Jan 2018
    Posts
    39

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    me.invoke means it works synchronously on same thread & Me.Begininvoke means it works asynchornously on a threadpool thread.

    When I use Me. Invoke, my data is passed to Main UI thread and gets processed . However I still do not understand why my data gets corrupted in between when I use Me. Invoke but my UI is running fine & responsive.

    When I use Me.BeginInvoke, My data is correct but UI starts hanging up.

    Iam still not able to understand the difference between the two methods.

    How can I use Me. Invoke correctly?

  18. #18
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,754

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    Please show the code.
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  19. #19
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    Quote Originally Posted by Vinod Chauhan View Post
    me.invoke means it works synchronously on same thread & Me.Begininvoke means it works asynchornously on a threadpool thread.

    When I use Me. Invoke, my data is passed to Main UI thread and gets processed . However I still do not understand why my data gets corrupted in between when I use Me. Invoke but my UI is running fine & responsive.

    When I use Me.BeginInvoke, My data is correct but UI starts hanging up.

    Iam still not able to understand the difference between the two methods.

    How can I use Me. Invoke correctly?
    Most likely, when you use Invoke, then you are suspending the thread the ReceivedData event used for the event, and the Gui Thread is released to process events, in particular the Invocation that you did from that suspended thread. So, while you're doing the drawing in the GUI thread, most likely there are other events pending so you process those, and one of those pending events can be another ReceivedData event on another thread. The Serial driver won't use the same background thread for the ReceivedData event if you have that thread tied up, so it generates a ReceivedData event on another thread. So, you may be processing another ReceivedData event while not have actually finished the the first thread, i.e. you haven't returned from the invocation yet because other events are pending.
    It appears your drawing takes long enough that you probably have a number of background threads pending from backed up ReceivedData events to be processed, and you may be processing those out of order, so messing up your data, or it is possible that the threads get backed up enough so that you end up loosing Serial data because you overflow the serial buffer.

    When you use BeginInvoke, the invocation is queued and will be processed the next time the GUI thread is allowed to run to process the event caused by the invocation. Thus you don't loose serial data, because you return immediately after queuing the event and exit the background thread you got the ReceivedData event in. The Serial data doesn't get backed up so you don't loose serial data, but you end up with a lot of invocations building up for the GUI thread to process, and thus your GUI processing gets quite slow.

    Redoing your drawing for each point received is not a very efficient way to handle drawing anyway.
    What I generally do is decide what speed I want to update the GUI and have a timer fire at that rate, say 10hz.
    I collect data continually, and at the tick of the "Gui Clock" I plot whatever data I currently have collected. If I'm receiving 100 data points per second, I'm not updating the plot 100 times per second, but adding 10 points to the plot each time the clock ticks, so do 10 times less drawing, which helps keep the GUI free to process regular events.

    Likewise, as I said, if there is a case where I may have many thousands of things to plot, then I will end up using a background thread to do the plotting instead, i.e. write to a bitmap and only invoke once from that background thread to update the plot from that bitmap. That way the drawing process itself won't impact the GUI thread or the serial threads.
    You can use a concurrent queue to transfer data from the received data thread to the Gui (or other) thread, and have that thread read from the concurrent queue. Use of a concurrent queue takes care of the handshaking needed when two threads are accessing the same object, so that they don't conflict, but it is still best to minimize the time accessing the concurrent queue from either thread so you don't hangup the access to the other thread for long.
    Last edited by passel; Sep 9th, 2020 at 11:04 AM.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  20. #20

    Thread Starter
    Member
    Join Date
    Jan 2018
    Posts
    39

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    Hi,

    Iam atatching the pictures of GUI for your reference to show the issue.

    Data with begininvoke
    Attachment 178661

    data with invoke method
    Attachment 178662

    below is the code

    Code:
    Public Delegate Sub MyDelegate(ByVal indata1 As Integer)
      Private ReadSerialPortTask As task
    
      Public mygraphics As Graphics
        Public p2 As New Pen(Color.Black, 0.2)
        Private Plotting_Signal As New Bitmap(100, 100)
    
    Private ReadWait As New Threading.AutoResetEvent(False)
    
     Private Sub SerialPort1_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
           
            ReadWait.Set() 'cause ReadSerialPort to run
        End Sub
    
    Private Sub ReadSerialPort()
            '
            'this is run as a Background task
            '
            Dim data As New System.Text.StringBuilder(1024 * 1024) 'accumulate SerialPort data here
            ' Dim data1(1024 * 1024) As String
            ' Dim data2(1024 * 1024) As String
            Dim mess As New System.Text.StringBuilder 'individual message
            Dim foundMess As Boolean = False
            Dim er As Integer
    
            Do
                ReadWait.WaitOne() 'wait for SerialPort1.DataReceived
    
                Do While SerialPort1.BytesToRead > 0 'accumulate all available bytes
                    data.Append(SerialPort1.ReadExisting)
                    'datastring = SerialPort1.ReadLine
                    ''data1(er) = datastring
                    ''er = er + 1
                    'datapacket = Integer.Parse(datastring)
    
                    'Me.BeginInvoke((New MyDelegate(AddressOf DrawGraph2)), datapacket)
    
                Loop
                Do 'process message, if one available
    
                    mess.Length = 0 'reset message
                    foundMess = False 'not found
                    Dim idx As Integer = 0
                    For idx = 0 To data.Length - 1 'look for CR??????
                        'data1(er) = data(idx)
                        If data(idx) = Constants.vbLf Then '<<<<<<<<<<<<<<<<<<<<<<<
                            '    'note that the CR will NOT be in mess
                            foundMess = True 'found message
                            Exit For
                            '    'ElseIf data(idx) = ControlChars.Lf Then
                            '    '    Continue For
                        End If
                        mess.Append(data(idx))
    
                    Next
                    If foundMess Then
                        data.Remove(0, idx + 1) 'remove found message from data
                        '
                        'process your message here <<<<<<<<<<<<
                        '
                        Dim datapacket As Integer
                        'Dim datapacket1 As String
                        'datapacket1 = mess.ToString
                        'data2(er) = datapacket1
                        'er = er + 1
                        ' datapacket = Integer.Parse(mess.ToString)
                        If Integer.TryParse(mess.ToString, datapacket) Then
                            Me.Invoke((New MyDelegate(AddressOf DrawGraph2)), datapacket)
                            'Else
                            '  invalid
                        End If
                    End If
    
                    'look for more messages in data?
                Loop While foundMess AndAlso data.Length > 0
            Loop
        End Sub
    
     Private Sub DrawGraph2(XVALUE1 As Integer)
    // all data processing code
    Plot_Signal = True
    Plot_Signal_Picture() // create bitmap picture
    mygraphics = Plotting_Panel.CreateGraphics // panel on which drawing takes place
    mygraphics.DrawImage(Plotting_Signal, 0, 0)
    End Sub
    
     Function Plot_Signal_Picture()
    
     Plotting_Signal.Dispose()
    Plotting_Signal = New Bitmap(Plotting_Panel.Width, Plotting_Panel.Height)
    
    If Plot_Signal = True Then
     mygraphics = Graphics.FromImage(Plotting_Signal)
                mygraphics.PageUnit = GraphicsUnit.Pixel
                mygraphics.PageScale = 1
                mygraphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
                mygraphics.ScaleTransform(1, 1)
    
    Case 16
     // this is case 16 to plot 16 different lines of data as shown in the picture attached.
                        For n = 0 To gMAX_SAMPLES - 1
                            Ch1_y2 = Intfilterbuffer(n, 0)
                            If Ch1_y2 > (Deflection * Pixels_Per_MM) Then
                                Ch1_y2 = Deflection * Pixels_Per_MM
                            ElseIf Ch1_y2 < (-1 * (Deflection * Pixels_Per_MM)) Then
                                Ch1_y2 = (Deflection * Pixels_Per_MM) * -1
                            End If
                            Ch2_y2 = Intfilterbuffer(n, 1)
                            If Ch2_y2 > (Deflection * Pixels_Per_MM) Then
                                Ch2_y2 = Deflection * Pixels_Per_MM
                            ElseIf Ch2_y2 < (-1 * (Deflection * Pixels_Per_MM)) Then
                                Ch2_y2 = (Deflection * Pixels_Per_MM) * -1
                            End If
                            Ch3_y2 = Intfilterbuffer(n, 2)
                            If Ch3_y2 > (Deflection * Pixels_Per_MM) Then
                                Ch3_y2 = Deflection * Pixels_Per_MM
                            ElseIf Ch3_y2 < (-1 * (Deflection * Pixels_Per_MM)) Then
                                Ch3_y2 = (Deflection * Pixels_Per_MM) * -1
                            End If
                            Ch4_y2 = Intfilterbuffer(n, 3)
                            If Ch4_y2 > (Deflection * Pixels_Per_MM) Then
                                    Ch4_y2 = Deflection * Pixels_Per_MM
                                ElseIf Ch4_y2 < (-1 * (Deflection * Pixels_Per_MM)) Then
                                    Ch4_y2 = (Deflection * Pixels_Per_MM) * -1
                                End If
                            Ch5_y2 = Intfilterbuffer(n, 4)
                            If Ch5_y2 > (Deflection * Pixels_Per_MM) Then
                                    Ch5_y2 = Deflection * Pixels_Per_MM
                                ElseIf Ch5_y2 < (-1 * (Deflection * Pixels_Per_MM)) Then
                                    Ch5_y2 = (Deflection * Pixels_Per_MM) * -1
                                End If
                            Ch6_y2 = Intfilterbuffer(n, 5)
                            If Ch6_y2 > (Deflection * Pixels_Per_MM) Then
                                    Ch6_y2 = Deflection * Pixels_Per_MM
                                ElseIf Ch6_y2 < (-1 * (Deflection * Pixels_Per_MM)) Then
                                    Ch6_y2 = (Deflection * Pixels_Per_MM) * -1
                                End If
                            Ch7_y2 = Intfilterbuffer(n, 6)
                            If Ch7_y2 > (Deflection * Pixels_Per_MM) Then
                                    Ch7_y2 = Deflection * Pixels_Per_MM
                                ElseIf Ch7_y2 < (-1 * (Deflection * Pixels_Per_MM)) Then
                                    Ch7_y2 = (Deflection * Pixels_Per_MM) * -1
                                End If
                            Ch8_y2 = Intfilterbuffer(n, 7)
                            If Ch8_y2 > (Deflection * Pixels_Per_MM) Then
                                    Ch8_y2 = Deflection * Pixels_Per_MM
                                ElseIf Ch8_y2 < (-1 * (Deflection * Pixels_Per_MM)) Then
                                    Ch8_y2 = (Deflection * Pixels_Per_MM) * -1
                                End If
                            Ch9_y2 = Intfilterbuffer(n, 8)
                            If Ch9_y2 > (Deflection * Pixels_Per_MM) Then
                                    Ch9_y2 = Deflection * Pixels_Per_MM
                                ElseIf Ch9_y2 < (-1 * (Deflection * Pixels_Per_MM)) Then
                                    Ch9_y2 = (Deflection * Pixels_Per_MM) * -1
                                End If
                            Ch10_y2 = Intfilterbuffer(n, 9)
                            If Ch10_y2 > (Deflection * Pixels_Per_MM) Then
                                    Ch10_y2 = Deflection * Pixels_Per_MM
                                ElseIf Ch10_y2 < (-1 * (Deflection * Pixels_Per_MM)) Then
                                    Ch10_y2 = (Deflection * Pixels_Per_MM) * -1
                                End If
                            Ch11_y2 = Intfilterbuffer(n, 10)
                            If Ch11_y2 > (Deflection * Pixels_Per_MM) Then
                                    Ch11_y2 = Deflection * Pixels_Per_MM
                                ElseIf Ch11_y2 < (-1 * (Deflection * Pixels_Per_MM)) Then
                                    Ch11_y2 = (Deflection * Pixels_Per_MM) * -1
                                End If
                            Ch12_y2 = Intfilterbuffer(n, 11)
                            If Ch12_y2 > (Deflection * Pixels_Per_MM) Then
                                    Ch12_y2 = Deflection * Pixels_Per_MM
                                ElseIf Ch12_y2 < (-1 * (Deflection * Pixels_Per_MM)) Then
                                    Ch12_y2 = (Deflection * Pixels_Per_MM) * -1
                                End If
                            Ch13_y2 = Intfilterbuffer(n, 12)
                            If Ch13_y2 > (Deflection * Pixels_Per_MM) Then
                                    Ch13_y2 = Deflection * Pixels_Per_MM
                                ElseIf Ch13_y2 < (-1 * (Deflection * Pixels_Per_MM)) Then
                                    Ch13_y2 = (Deflection * Pixels_Per_MM) * -1
                                End If
                            Ch14_y2 = Intfilterbuffer(n, 13)
                            If Ch14_y2 > (Deflection * Pixels_Per_MM) Then
                                    Ch14_y2 = Deflection * Pixels_Per_MM
                                ElseIf Ch14_y2 < (-1 * (Deflection * Pixels_Per_MM)) Then
                                    Ch14_y2 = (Deflection * Pixels_Per_MM) * -1
                                End If
                            Ch15_y2 = Intfilterbuffer(n, 14)
                            If Ch15_y2 > (Deflection * Pixels_Per_MM) Then
                                    Ch15_y2 = Deflection * Pixels_Per_MM
                                ElseIf Ch15_y2 < (-1 * (Deflection * Pixels_Per_MM)) Then
                                    Ch15_y2 = (Deflection * Pixels_Per_MM) * -1
                                End If
                            Ch16_y2 = Intfilterbuffer(n, 15)
                            If Ch16_y2 > (Deflection * Pixels_Per_MM) Then
                                    Ch16_y2 = Deflection * Pixels_Per_MM
                                ElseIf Ch16_y2 < (-1 * (Deflection * Pixels_Per_MM)) Then
                                    Ch16_y2 = (Deflection * Pixels_Per_MM) * -1
                                End If
    
                                O1currentX = O1lastX + Sweep_factor
                                Ch1_y2 = Ch1_y2 + 1 * Channel_Area
                                Ch2_y2 = Ch2_y2 + 2 * Channel_Area
                                Ch3_y2 = Ch3_y2 + 3 * Channel_Area
                                Ch4_y2 = Ch4_y2 + 4 * Channel_Area
                                Ch5_y2 = Ch5_y2 + 5 * Channel_Area
                                Ch6_y2 = Ch6_y2 + 6 * Channel_Area
                                Ch7_y2 = Ch7_y2 + 7 * Channel_Area
                                Ch8_y2 = Ch8_y2 + 8 * Channel_Area
                                Ch9_y2 = Ch9_y2 + 9 * Channel_Area
                                Ch10_y2 = Ch10_y2 + 10 * Channel_Area
                                Ch11_y2 = Ch11_y2 + 11 * Channel_Area
                                Ch12_y2 = Ch12_y2 + 12 * Channel_Area
                                Ch13_y2 = Ch13_y2 + 13 * Channel_Area
                                Ch14_y2 = Ch14_y2 + 14 * Channel_Area
                                Ch15_y2 = Ch15_y2 + 15 * Channel_Area
                                Ch16_y2 = Ch16_y2 + 16 * Channel_Area
    
                                p2.Color = Label2.ForeColor
                                mygraphics.DrawLine(p2, O1lastX, Ch1_y1, O1currentX, Ch1_y2)
                                p2.Color = Label3.ForeColor
                                mygraphics.DrawLine(p2, O1lastX, Ch2_y1, O1currentX, Ch2_y2)
                                p2.Color = Label4.ForeColor
                                mygraphics.DrawLine(p2, O1lastX, Ch3_y1, O1currentX, Ch3_y2)
                                p2.Color = Label5.ForeColor
                                mygraphics.DrawLine(p2, O1lastX, Ch4_y1, O1currentX, Ch4_y2)
                                p2.Color = Label6.ForeColor
                                mygraphics.DrawLine(p2, O1lastX, Ch5_y1, O1currentX, Ch5_y2)
                                p2.Color = Label7.ForeColor
                                mygraphics.DrawLine(p2, O1lastX, Ch6_y1, O1currentX, Ch6_y2)
                                p2.Color = Label8.ForeColor
                                mygraphics.DrawLine(p2, O1lastX, Ch7_y1, O1currentX, Ch7_y2)
                                p2.Color = Label9.ForeColor
                                mygraphics.DrawLine(p2, O1lastX, Ch8_y1, O1currentX, Ch8_y2)
                                p2.Color = Label10.ForeColor
                                mygraphics.DrawLine(p2, O1lastX, Ch9_y1, O1currentX, Ch9_y2)
                                p2.Color = Label11.ForeColor
                                mygraphics.DrawLine(p2, O1lastX, Ch10_y1, O1currentX, Ch10_y2)
                                p2.Color = Label12.ForeColor
                                mygraphics.DrawLine(p2, O1lastX, Ch11_y1, O1currentX, Ch11_y2)
                                p2.Color = Label13.ForeColor
                                mygraphics.DrawLine(p2, O1lastX, Ch12_y1, O1currentX, Ch12_y2)
                                p2.Color = Label14.ForeColor
                                mygraphics.DrawLine(p2, O1lastX, Ch13_y1, O1currentX, Ch13_y2)
                                p2.Color = Label15.ForeColor
                                mygraphics.DrawLine(p2, O1lastX, Ch14_y1, O1currentX, Ch14_y2)
                                p2.Color = Label16.ForeColor
                                mygraphics.DrawLine(p2, O1lastX, Ch15_y1, O1currentX, Ch15_y2)
                                p2.Color = Label17.ForeColor
                                mygraphics.DrawLine(p2, O1lastX, Ch16_y1, O1currentX, Ch16_y2)
    
    
    
                                Ch1_y1 = Ch1_y2
                                Ch2_y1 = Ch2_y2
                                Ch3_y1 = Ch3_y2
                                Ch4_y1 = Ch4_y2
                                Ch5_y1 = Ch5_y2
                                Ch6_y1 = Ch6_y2
                                Ch7_y1 = Ch7_y2
                                Ch8_y1 = Ch8_y2
                                Ch9_y1 = Ch9_y2
                                Ch10_y1 = Ch10_y2
                                Ch11_y1 = Ch11_y2
                                Ch12_y1 = Ch12_y2
                                Ch13_y1 = Ch13_y2
                                Ch14_y1 = Ch14_y2
                                Ch15_y1 = Ch15_y2
                                Ch16_y1 = Ch16_y2
    
                            O1lastX = O1currentX
                            If O1lastX >= Plotting_Panel.Width Then
                                O1currentX = 0
                                O1lastX = 0
                                mygraphics.Clear(Color.LightYellow)
                                Plotting_Panel.Invalidate()
                            End If
                        Next
    End If
    End Function

  21. #21

    Thread Starter
    Member
    Join Date
    Jan 2018
    Posts
    39

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    Data with begininvoke
    Attachment 178663

    data with invoke

    Name:  invoke.jpg
Views: 549
Size:  52.5 KB

    I don't know if it is attached correctly or not.
    Attached Images Attached Images  

  22. #22
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    Since you're drawing into a bitmap, you could do all that drawing in a background thread.
    You would only need to invoke when you wanted to update the panel with the result.

    Your drawing process is the really slow part of this application, so I'm sure you're receiving serial data faster than you can draw it. When you use BeginInvoke, the drawing looks good, but I think it is really falling further and further behind the data being received, i.e. it lags the realtime data more and more as time goes on. The GUI thread is overloaded, which is why it is slow, as it draws as fast as it can so is using up almost all of the its time just doing the drawing.

    When you use invoke, then the receiving thread is tied to the GUI, so your receiving thread is slowed down, to the speed that you can do your drawing at, which is slower than the rate you are receiving data, so you end up loosing data, but the GUI is responsive because you don't end up with a backlog of drawing events stacking up on the GUI thread.

    Even the following example which is not doing a lot of drawing, takes longer to draw than the number of values being generated by the simulated ReadLine code.
    When the code finishes updating the panel, and loops back to wait, it doesn't really wait, because there are already five or more items in the concurrent queue that were enqueued during the time it was drawing.

    Anyway, here is the code I was testing with. I create the panel in code, so you don't have to create the panel in the IDE to run the example. Just paste the code in a new project and run.
    Code:
    Imports System.Threading
    
    Public Class Form1
    
      Private ReadThread As New Thread(AddressOf ReadThreadProc)
      Private DrawThread As New Thread(AddressOf DrawThreadProc)
    
      Private DrawWait As New AutoResetEvent(False)
      Private panelBitMap As New Bitmap(10, 10)
      Private drawBitMap As New Bitmap(10, 10)
    
      Private WithEvents panel1 As New Panel
    
      Private rand As New Random
      Private dataQueue As New Collections.Concurrent.ConcurrentQueue(Of Integer)
      Private running As Boolean = True
    
      Private Sub ReadThreadProc()
        Dim datapacket As Integer
        Dim dataString As String
        Dim rcounter As Long
    
        Do While running
    
          'dataString = SerialPort1.Readline
    
          'simulate SerialPort1.readline
          dataString = (100 - rand.Next(200)).ToString
          Thread.Sleep(1)
          'end of serialport1.readline emulation
    
          datapacket = Integer.Parse(dataString)
          dataQueue.Enqueue(datapacket)
          '  rcounter += 1
          '  Debug.Print("rcount {0}", rcounter.ToString)
          DrawWait.Set()
        Loop
      End Sub
    
      Private Sub DrawThreadProc()
        Dim X As Integer, lastX As Integer
        Dim Y As Integer, lastY As Integer
        Dim g As Graphics
        Dim dcounter As Long
        Dim qcount As Integer
        Do
          DrawWait.WaitOne()
          '  dcounter += 1
          '  Debug.Print("dcount {0}", dcounter.ToString)
          If running Then
            g = Graphics.FromImage(drawBitMap)
    
            Do While dataQueue.TryDequeue(Y)
              qcount += 1
              X += 1
              If X > drawBitMap.Width Then
                X = 0
                lastX = -1
                g.Clear(Color.LightYellow)
              End If
              g.DrawLine(Pens.Blue, lastX, lastY + 200, X, Y + 200)
              lastX = X
              lastY = Y
            Loop
            '   Debug.Print("qcount {0}", qcount.ToString)
            '   qcount = 0
            panelBitMap.Dispose()
            panelBitMap = CType(drawBitMap.Clone, Bitmap)
            Me.Invoke(Sub()
                        Using gp As Graphics = panel1.CreateGraphics
                          gp.DrawImage(panelBitMap, 0, 0)
                        End Using
                      End Sub)
    
          End If
        Loop While running
        Me.Invoke(Sub() Me.Close())  'allow the form to close now
      End Sub
    
      Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        If running Then
          e.Cancel = True
        End If
        running = False 'let threads exit, in particular the one invoking back to the form
      End Sub
    
    
      Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        Controls.Add(panel1)
        panel1.Bounds = (New Rectangle(10, 10, 600, 400))
        drawBitMap.Dispose()
        drawBitMap = New Bitmap(panel1.ClientSize.Width, panel1.ClientSize.Height)
        Using g = Graphics.FromImage(drawBitMap)
          g.Clear(Color.LightYellow)
        End Using
        DrawThread.IsBackground = True
        DrawThread.Start()
        ReadThread.IsBackground = True
        ReadThread.Start()
    
      End Sub
    End Class
    You didn't show how you took the data input, and spread it across your filter buffers to get 16 lines, but if you do all that and the drawing in a background thread, and only do the final panel update by invoking, your GUI should be a lot more responsive.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  23. #23

    Thread Starter
    Member
    Join Date
    Jan 2018
    Posts
    39

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    Hi,

    Where Iam using Me.Invoke((New MyDelegate(AddressOf DrawGraph2)), datapacket), This is passing my data to drawgraph2 function which is running on Main UI thread. So instead of passing data to drawgraph2 I need to pass data to a another background thread.

    Instead of using me.invoke I simple called DrawGraph2(datapacket). I used another thread called Draw_Function_For_Thread and start it in form load.
    But It goes inside the thread only once during load. There after it never goes inside the new thread which I created for drawing bitmap and invoking the bitmap to main UI Thread.

    I tried below code

    Code:
    Private DrawThread As New Thread(AddressOf Draw_Function_For_Thread)
    
    Private ReadSerialPortTask As task
    
    Private Sub Acquire_Load(sender As Object, e As EventArgs) Handles MyBase.Load
          
            Dim monitorWidth As Integer = My.Computer.Screen.WorkingArea.Size.Width
            Dim monitorHeight As Integer = My.Computer.Screen.WorkingArea.Size.Height
            ' --- adjust size of this form ** this does NOT make consideration of DPI (eg. 125%, 150%) **
            Me.Width = monitorWidth
            Me.Height = monitorHeight
            Control.CheckForIllegalCrossThreadCalls = False
            Plotting_Signal = New Bitmap(Plotting_Panel.Width, Plotting_Panel.Height)
            Dim g As Graphics = Me.CreateGraphics
            Monitor_PPI_On_Y = g.DpiY
            Pixels_Per_MM = Monitor_PPI_On_Y / 25.4
            
            DrawThread.IsBackground = True
            DrawThread.Start()
    
    
        End Sub
    Private Sub SerialPort1_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
                 
            ReadWait.Set() 'cause ReadSerialPort to run
        End Sub
    
    
        Private ReadWait As New Threading.AutoResetEvent(False)
        Private Sub ReadSerialPort()
            '
            'this is run as a Background task
            '
            Dim data As New System.Text.StringBuilder(1024 * 1024) 'accumulate SerialPort data here
      
            Dim mess As New System.Text.StringBuilder 'individual message
            Dim foundMess As Boolean = False
            Dim er As Integer
    
            Do
                ReadWait.WaitOne() 'wait for SerialPort1.DataReceived
    
                Do While SerialPort1.BytesToRead > 0 'accumulate all available bytes
                    data.Append(SerialPort1.ReadExisting)
                                
                Loop
                Do 'process message, if one available
    
                    mess.Length = 0 'reset message
                    foundMess = False 'not found
                    Dim idx As Integer = 0
                    For idx = 0 To data.Length - 1 'look for CR??????
                        'data1(er) = data(idx)
                        If data(idx) = Constants.vbLf Then '<<<<<<<<<<<<<<<<<<<<<<<
                            '    'note that the CR will NOT be in mess
                            foundMess = True 'found message
                            Exit For
                            '    'ElseIf data(idx) = ControlChars.Lf Then
                            '    '    Continue For
                        End If
                        mess.Append(data(idx))
    
                    Next
                    If foundMess Then
                        data.Remove(0, idx + 1) 'remove found message from data
                        '
                        'process your message here <<<<<<<<<<<<
                        '
                        Dim datapacket As Integer
                       
                        If Integer.TryParse(mess.ToString, datapacket) Then
                            ' Me.Invoke((New MyDelegate(AddressOf DrawGraph2)), datapacket)
                            DrawGraph2(datapacket)
                           
                        End If
                    End If
    
                    
                Loop While foundMess AndAlso data.Length > 0
            Loop
        End Sub
    
    Private Sub DrawGraph2(XVALUE1 As Integer)
    
    If transmission = "a" Then
    
     
     Plot_Signal = True
    End Sub
    
    Public Sub Draw_Function_For_Thread()
            If Plot_Signal = True Then
                Plot_Signal_Picture()
                Me.Invoke(Sub()
                              mygraphics = Plotting_Panel.CreateGraphics
                              mygraphics.DrawImage(Plotting_Signal, 0, 0)
                          End Sub)
                Plot_Signal = False
            End If
        End Sub

  24. #24
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    There is no loop in your Draw_Function_For_Thread so you start the thread, it runs through and exits and that is the end of the thread.

    You used ReadWait to pause your SerialPort reading thread, until you had data, likewise in my example I used DrawWait to pause the Drawing thread until I had data to draw. In both those threads, you see that code is inside a loop, so the thread continues to loop, it doesn't exit.

    Instead of using a boolean, Plot_Signal, to try to trigger the thread, you need to wait on something (in this case, we're using a Threading.AutoResetEvent object to do the waiting).
    You also need a loop so you don't exit the thread, just loop back up and wait for the next event.

    In my case, I passed the value in a queue rather than a parameter, because it allows passing more than one value at a time (in a sense), especially in the case where it takes so long to draw.
    You probably want to change your drawing so that you can add all the values you receive to your channel filter arrays and only draw when you don't have any more values pending from your serial stream. That way you can keep up with the serial data. You probably don't realize that while the data looks good, it is probably lagging the serial stream by more and more as time passes.

    I've had the issue before where the data we displayed fell slowly behind the data that was being generated and we didn't realize it until we noticed the lag in reaction of what was being displayed to control inputs which should have had immediate effect on the visual display.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  25. #25

    Thread Starter
    Member
    Join Date
    Jan 2018
    Posts
    39

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    Hi,

    I tried the code using background thread for processing all the data and only invoking the main UI once after all the processing. But the problem is that the background thread is really slow as compared to the main UI Thread. The same data processing and plotting is fast in the Main UI thread as compared to the same work done in background thread. I also tried to increase the thread priority to highest level , but still It is very slow.
    When I plot in the Main UI Thread I see instant real time change in signal, But the same work in background thread the real time change is not seen and it keeps lagging further and further.

    Below is the code I tried. I'am posting the complete code. I have cut short my data plotting code as short as I could.

    Code:
    Private DrawThread As New Thread(AddressOf Draw_Function_For_Thread)
    Private ReadSerialPortTask As Task
     Private ReadWait As New Threading.AutoResetEvent(False)
     Private dataQueue As New Collections.Concurrent.ConcurrentQueue(Of Integer)
    public boolean running = false
     Private Sub Acquire_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
    //other initilizatons
     running  = true
     DrawThread.Priority = ThreadPriorityLevel.Highest
     DrawThread.IsBackground = True
     DrawThread.Start()
     End Sub
    
     Private Sub Acquire_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
            ReadSerialPortTask = Task.Factory.StartNew(Sub() ReadSerialPort())
           
        End Sub
    
    Private Sub SerialPort1_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
            ReadWait.Set() 'cause ReadSerialPort to run
        End Sub
    
     Private Sub ReadSerialPort()
            '
            'this is run as a Background task
            '
            Dim data As New System.Text.StringBuilder(1024 * 1024) 'accumulate SerialPort data here
            ' Dim data1(1024 * 1024) As String
            ' Dim data2(1024 * 1024) As String
            Dim mess As New System.Text.StringBuilder 'individual message
            Dim foundMess As Boolean = False
            Dim er As Integer
    
            Do
                ReadWait.WaitOne() 'wait for SerialPort1.DataReceived
    
                Do While SerialPort1.BytesToRead > 0 'accumulate all available bytes
                    data.Append(SerialPort1.ReadExisting)
                    
                   
                Loop
                Do 'process message, if one available
    
                    mess.Length = 0 'reset message
                    foundMess = False 'not found
                    Dim idx As Integer = 0
                    For idx = 0 To data.Length - 1 'look for CR??????
                       
                        If data(idx) = Constants.vbLf Then '<<<<<<<<<<<<<<<<<<<<<<<
                            '    'note that the CR will NOT be in mess
                            foundMess = True 'found message
                            Exit For
                            
                        End If
                        mess.Append(data(idx))
    
                    Next
                    If foundMess Then
                        data.Remove(0, idx + 1) 'remove found message from data
                        '
                        'process your message here <<<<<<<<<<<<
                        '
                        Dim datapacket As Integer
                                                                         
                        If Integer.TryParse(mess.ToString, datapacket) Then
                           
                            dataQueue.Enqueue(datapacket)
                                          
                        End If
                    End If
    
                    'look for more messages in data?
                Loop While foundMess AndAlso data.Length > 0
            Loop
        End Sub
    
     Private Sub Draw_Function_For_Thread()
            Do
              
                Do While dataQueue.TryDequeue(ssst)
    
                    DrawGraph2(datapacket)
    
                    If Plot_Signal = True Then
                        Plot_Signal = False
                                            
                        Me.Invoke(Sub()
                                      Using gp As Graphics = Plotting_Panel.CreateGraphics
                                          gp.DrawImage(Plotting_Signal, 0, 0)
                                      End Using
                                  End Sub)
                        Dim second As Long = seconds
                        Plotting_Signal.Dispose()
                        Plotting_Signal = New Bitmap(Plotting_Panel.Width, Plotting_Panel.Height)
                        '''''For Minor Grid
                        If Minor_grid = True Then
                            If Sweep7_5 = True Then
                                Dim Minor_gridFactor As Single = Plotting_Panel.Width / (40 * 5)
                                Dim Minor_gridPen As New Pen(Color.LightGray, 1)
                                Dim i As Double
                                mygraphics = Graphics.FromImage(Plotting_Signal)
    
                                For i = 0 To Plotting_Panel.Width Step Minor_gridFactor
                                    mygraphics.DrawLine(Minor_gridPen, CInt(i), 0, CInt(i), Plotting_Panel.Height)
                                Next
    
    
                            ElseIf Sweep15 = True Then
                                Dim Minor_gridFactor As Single = Plotting_Panel.Width / (20 * 5)
                                Dim Minor_gridPen As New Pen(Color.LightGray, 1)
                                Dim i As Double
                                mygraphics = Graphics.FromImage(Plotting_Signal)
    
                                For i = 0 To Plotting_Panel.Width Step Minor_gridFactor
                                    mygraphics.DrawLine(Minor_gridPen, CInt(i), 0, CInt(i), Plotting_Panel.Height)
                                Next
    
                            ElseIf Sweep30 = True Then
    
                                Dim Minor_gridFactor As Single = Plotting_Panel.Width / (10 * 5)
                                Dim Minor_gridPen As New Pen(Color.LightGray, 1)
                                Dim i As Double
                                mygraphics = Graphics.FromImage(Plotting_Signal)
    
                                For i = 0 To Plotting_Panel.Width Step Minor_gridFactor
                                    mygraphics.DrawLine(Minor_gridPen, CInt(i), 0, CInt(i), Plotting_Panel.Height)
                                Next
    
    
                            ElseIf Sweep60 = True Then
                                Dim Minor_gridFactor As Single = Plotting_Panel.Width / (5 * 5)
                                Dim Minor_gridPen As New Pen(Color.LightGray, 1)
                                Dim i As Double
                                mygraphics = Graphics.FromImage(Plotting_Signal)
                                For i = 0 To Plotting_Panel.Width Step Minor_gridFactor
                                    mygraphics.DrawLine(Minor_gridPen, CInt(i), 0, CInt(i), Plotting_Panel.Height)
                                Next
    
                            End If
                        End If
                        ''''For Majjor Grid
                        If Major_grid = True Then
    
                            Select Case True
                                Case Sweep7_5
                                    mygraphics = Graphics.FromImage(Plotting_Signal)
                                    Dim Major_gridFactor As Single = Plotting_Panel.Width / 40
                                    Dim Major_gridPen As New Pen(Color.Black, 1)
                                    Dim brush As New SolidBrush(Color.Black)
                                    Dim TimeFont As New Font("Arial", 13)
                                    Dim i As Double
                                    For i = 0 To Plotting_Panel.Width Step Major_gridFactor
                                        mygraphics.DrawLine(Major_gridPen, CInt(i), 0, CInt(i), Plotting_Panel.Height)
                                        second = second + 1
                                        mygraphics.DrawString(TimeDisplay(second), TimeFont, brush, (i + 1), (Plotting_Panel.Height - 50))
                                    Next
    
                                Case Sweep15
                                    mygraphics = Graphics.FromImage(Plotting_Signal)
                                    Dim Major_gridFactor As Single = Plotting_Panel.Width / 20
                                    Dim Major_gridPen As New Pen(Color.Black, 1)
                                    Dim brush As New SolidBrush(Color.Black)
                                    Dim TimeFont As New Font("Arial", 13)
    
                                    Dim i As Double
    
                                    For i = 0 To Plotting_Panel.Width Step Major_gridFactor
                                        mygraphics.DrawLine(Major_gridPen, CInt(i), 0, CInt(i), Plotting_Panel.Height)
                                        second = second + 1
                                        mygraphics.DrawString(TimeDisplay(second), TimeFont, brush, (i + 1), (Plotting_Panel.Height - 50))
                                    Next
    
                                Case Sweep30
                                    mygraphics = Graphics.FromImage(Plotting_Signal)
                                    Dim Major_gridFactor As Single = Plotting_Panel.Width / 10
                                    Dim Major_gridPen As New Pen(Color.Black, 1)
                                    Dim brush As New SolidBrush(Color.Black)
                                    Dim TimeFont As New Font("Arial", 13)
    
                                    Dim i As Double
                                    For i = 0 To Plotting_Panel.Width Step Major_gridFactor
                                        mygraphics.DrawLine(Major_gridPen, CInt(i), 0, CInt(i), Plotting_Panel.Height)
                                        second = second + 1
                                        mygraphics.DrawString(TimeDisplay(second), TimeFont, brush, (i + 1), (Plotting_Panel.Height - 50))
                                    Next
    
                                Case Sweep60
                                    mygraphics = Graphics.FromImage(Plotting_Signal)
                                    Dim Major_gridFactor As Single = Plotting_Panel.Width / 5
                                    Dim Major_gridPen As New Pen(Color.Black, 1)
                                    Dim brush As New SolidBrush(Color.Black)
                                    Dim TimeFont As New Font("Arial", 13)
                                    Dim i As Double
                                    For i = 0 To Plotting_Panel.Width Step Major_gridFactor
                                        mygraphics.DrawLine(Major_gridPen, CInt(i), 0, CInt(i), Plotting_Panel.Height)
                                        second = second + 1
                                        mygraphics.DrawString(TimeDisplay(second), TimeFont, brush, (i + 1), (Plotting_Panel.Height - 50))
                                    Next
    
                            End Select
                        End If
    
    
                    End If
                Loop
                ' End If
            Loop While running
                Me.Invoke(Sub() Me.Close())  'allow the form to close now
        End Sub
    
     Private Sub DrawGraph2(XVALUE1 As Integer)
    
                           
    
    
                                    For sample = 0 To gMAX_SAMPLES - 1 ' no. of data values
                                        Plot_channel = Main_Panel_Channels_To_Display
                                        For channel = 0 To Plot_channel - 1 ' no. of lines to display
                                           // data processing to obtain final value  for filter buffer                                      
    
                                            mygraphics = Graphics.FromImage(Plotting_Signal)
                                            mygraphics.PageUnit = GraphicsUnit.Pixel
                                            mygraphics.PageScale = 1
                                            mygraphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
                                            mygraphics.ScaleTransform(1, 1)
                                                                                
                                            Ch1_y2 = Intfilterbuffer(sample, channel)
    
                                            If Ch1_y2 > (Deflection * Pixels_Per_MM) Then
                                                Ch1_y2 = Deflection * Pixels_Per_MM
                                            ElseIf Ch1_y2 < (-1 * (Deflection * Pixels_Per_MM)) Then
                                                Ch1_y2 = (Deflection * Pixels_Per_MM) * -1
                                            End If
    
                                            O1currentX = O1lastX + Sweep_factor
                                            Ch1_y2 = Ch1_y2 + (channel + 1) * Channel_Area
    
                                            p2.Color = panel1.Controls("Label" & (channel + 2).ToString).ForeColor
                                            mygraphics.DrawLine(p2, O1lastX, Ch1_y1(channel), O1currentX, Ch1_y2)
    
                                            Ch1_y1(channel) = Ch1_y2
                                            'Me.Invoke(Sub()
                                            '              Using gp As Graphics = Plotting_Panel.CreateGraphics
                                            '                  gp.DrawImage(Plotting_Signal, 0, 0)
                                            '              End Using
                                            '          End Sub)
    
                                        Next
                                        O1lastX = O1currentX
                                        If O1lastX >= Plotting_Panel.Width Then
                                            O1currentX = 0
                                            O1lastX = 0
                                            mygraphics.Clear(Color.LightYellow)
                                            'Plotting_Signal.Dispose()
                                            'Plotting_Signal = New Bitmap(Plotting_Panel.Width, Plotting_Panel.Height)
    
                                            Plotting_Panel.Invalidate()
                                        End If
                                    Next
                                 
                                    If transmission = "a" Then
    
                                        Plot_Signal = True
    
                                        'Using gp As Graphics = Plotting_Panel.CreateGraphics
                                        '    gp.DrawImage(Plotting_Signal, 0, 0)
                                        'End Using
                                                                           
                                    End If
                                       
        End Sub

  26. #26
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    If that is the complete code, then I guess you're out of luck.

    The following won't compile in any version of VB I tried.
    public boolean running = false

    The following is also a syntax error in VB 2010 and 2017 (I don't have 2015)
    //other initializatons

    Also you have the line
    DrawThread.Priority = ThreadPriorityLevel.Highest

    That doesn't make sense, and shouldn't be allowed, but you obviously don't have Option Strict On, so are allowing invalid coercion of types to take place.
    What you meant is:
    DrawThread.Priority = ThreadPriority.Highest

    That should have been provided to you in a list by intellisense in the IDE.
    ThreadPriority.Highest = 4
    ThreadPriorityLevel.Highest = 2

    So, you code is setting DrawThread.Priority to 2, not 4. 2 = ThreadPriority.Normal.

    Although, it probably wouldn't make much difference. You shouldn't be changing ThreadPrioirty in general anyway, and you can't expect it to make up for bad code.


    transmission isn't defined anywhere, nor is it set anywhere else in the code, this is the only reference to it.
    Code:
                                    If transmission = "a" Then
    
                                        Plot_Signal = True
    That is the only place Plot_Signal is set to True, so it must never be true, unless you have another module where these things are defined and manipulated.
    If Plot_Signal is not true, almost none of the stuff in the DrawFunction thread is done.
    You enqueue your Serial Data into the dataQueue, but when you dequeue, you don't use what you might have dequeued.
    You call DrawGraph2 with the current value of datapacket, which means you may have dropped some, or you use the same latest value of datapacket multiple times (how ever many versions of datapacket were queued.

    For instance, lets say while you were drawing, the numbers 1, 2, 3, 4, 5 were received and queued in the queue.
    When you loop back to the top and start to dequeue, datapacket is set to 5, i.e. the last value received.
    You dequeue the 1, but then draw using datapacket, so you draw 5.
    You dequeue 2, and you draw 5.
    You dequeue 3, and you draw 5
    You dequeue 4, and you draw 5
    You dequeue 5, and you draw 5

    I don't see Plotting_Signal declared anywhere.
    If Plotting_Signal was a bitmap, then I would be surprised you see any drawing because I don't see that the bitmap is drawn in any code that get's executed, i.e. where it is invoked is inside the "If Plot_Signal = True", which doesn't ever get set in the code you posted.

    You create a lot of graphical objects, i.e. graphic object, pens and brushes which you never dispose of. Also, you create copies of stock pens and brushes, so those are things you don't even have to create and dispose of. You can just use the pre-existing versions in the Pens and Brushes classes.

    Perhaps rather than continue to throw code at the problem, a discussion of design would be more productive. What is the environment you are dealing with, i.e. approximately how many points are you receiving from the Serial port per second? How do you determine how many traces to drawn, and how is the data coming in the Serial port assigned to a specific trace? I don't think the drawing should be refreshed to the screen for every point received, but perhaps is should be refreshed everytime you have all the points for all the traces for a specific time.
    If you could just update the latest portion of the traces, rather than the whole graph, that should be faster.

    If the drawing appears to be drawing slower and falling behind, compared to when you were drawing directly to the panel, it could be a perception thing, because your not updating the panel from your drawing as often as you should be. Or it could be when you were drawing to the panel directly, you were drawing the latest data you received, losing some intermediate data, so because you're drawing lines, you end up with a complete connected line in the graph, but it has essentially dropped some of the points in the line, so has in essence filtered out higher frequency data, drawing the graph at a lower resolution, allowing it to keep up with the data stream, although taking most of your GUI thread time to draw what it did draw.

    I don't know that I have the time to give you the help you need. I think the drawing needs to be more efficient, but it is hard to give good examples without knowing details of your data stream and how it is processed to give you plotting data. Knowing the speed of the data, i.e. the number of points per second you are receiving that need to be plotted would probably be a good reference so that a test case of feeding a stream of simulated data at that speed and plotting it could be used as a representative test case for coding examples.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  27. #27
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,754

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    Some changes, pay attention to haveDataPacket and its use. Agree with passel.

    Code:
        Private DrawThread As New Thread(AddressOf Draw_Function_For_Thread)
        Private ReadSerialPortTask As Task
        Private ReadWait As New Threading.AutoResetEvent(False)
        Private dataQueue As New Collections.Concurrent.ConcurrentQueue(Of Integer)
        Public running As Boolean = False
    
        Private Sub Acquire_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            ''other initilizatons
            running = True
            'DrawThread.Priority = ThreadPriorityLevel.Highest
            DrawThread.IsBackground = True
            DrawThread.Start()
        End Sub
    
        Private Sub Acquire_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
            ReadSerialPortTask = Task.Factory.StartNew(Sub() ReadSerialPort())
        End Sub
    
        Private Sub SerialPort1_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
            ReadWait.Set() 'cause ReadSerialPort to run
        End Sub
    
        Private Sub ReadSerialPort()
            '
            'this is run as a Background task
            '
            Dim data As New System.Text.StringBuilder(1024 * 1024) 'accumulate SerialPort data here
            ' Dim data1(1024 * 1024) As String
            ' Dim data2(1024 * 1024) As String
            Dim mess As New System.Text.StringBuilder 'individual message
            Dim foundMess As Boolean = False
            Dim er As Integer
    
            Do
                ReadWait.WaitOne() 'wait for SerialPort1.DataReceived
    
                Do While SerialPort1.BytesToRead > 0 'accumulate all available bytes
                    data.Append(SerialPort1.ReadExisting)
                Loop
                Do 'process message, if one available
    
                    mess.Length = 0 'reset message
                    foundMess = False 'not found
                    Dim idx As Integer = 0
                    For idx = 0 To data.Length - 1 'look for CR??????
    
                        If data(idx) = Constants.vbLf Then '<<<<<<<<<<<<<<<<<<<<<<<
                            '    'note that the CR will NOT be in mess
                            foundMess = True 'found message
                            Exit For
    
                        End If
                        mess.Append(data(idx))
    
                    Next
                    If foundMess Then
                        data.Remove(0, idx + 1) 'remove found message from data
                        '
                        'process your message here <<<<<<<<<<<<
                        '
                        Dim datapacket As Integer
    
                        If Integer.TryParse(mess.ToString, datapacket) Then
                            dataQueue.Enqueue(datapacket)
                            haveDataPacket.Set() '<<<<<<<<<<<<<<<
                        End If
                    End If
    
                    'look for more messages in data?
                Loop While foundMess AndAlso data.Length > 0
            Loop
        End Sub
    
        Private haveDataPacket As New Threading.ManualResetEvent(False) '<<<<<<<<<<<<<<<
        Private Sub Draw_Function_For_Thread()
            Do
                haveDataPacket.WaitOne() '<<<<<<<<<<<<<<<
                haveDataPacket.Reset() '<<<<<<<<<<<<<<<
                Do While dataQueue.TryDequeue(ssst)
                    DrawGraph2(datapacket)
                    If Plot_Signal = True Then
                        Plot_Signal = False
    
                        Me.Invoke(Sub()
                                      Using gp As Graphics = Plotting_Panel.CreateGraphics
                                          gp.DrawImage(Plotting_Signal, 0, 0)
                                      End Using
                                  End Sub)
                        Dim second As Long = seconds
                        Plotting_Signal.Dispose()
                        Plotting_Signal = New Bitmap(Plotting_Panel.Width, Plotting_Panel.Height)
                        '''''For Minor Grid
                        If Minor_grid = True Then
                            If Sweep7_5 = True Then
                                Dim Minor_gridFactor As Single = Plotting_Panel.Width / (40 * 5)
                                Dim Minor_gridPen As New Pen(Color.LightGray, 1)
                                Dim i As Double
                                mygraphics = Graphics.FromImage(Plotting_Signal)
    
                                For i = 0 To Plotting_Panel.Width Step Minor_gridFactor
                                    mygraphics.DrawLine(Minor_gridPen, CInt(i), 0, CInt(i), Plotting_Panel.Height)
                                Next
    
    
                            ElseIf Sweep15 = True Then
                                Dim Minor_gridFactor As Single = Plotting_Panel.Width / (20 * 5)
                                Dim Minor_gridPen As New Pen(Color.LightGray, 1)
                                Dim i As Double
                                mygraphics = Graphics.FromImage(Plotting_Signal)
    
                                For i = 0 To Plotting_Panel.Width Step Minor_gridFactor
                                    mygraphics.DrawLine(Minor_gridPen, CInt(i), 0, CInt(i), Plotting_Panel.Height)
                                Next
    
                            ElseIf Sweep30 = True Then
    
                                Dim Minor_gridFactor As Single = Plotting_Panel.Width / (10 * 5)
                                Dim Minor_gridPen As New Pen(Color.LightGray, 1)
                                Dim i As Double
                                mygraphics = Graphics.FromImage(Plotting_Signal)
    
                                For i = 0 To Plotting_Panel.Width Step Minor_gridFactor
                                    mygraphics.DrawLine(Minor_gridPen, CInt(i), 0, CInt(i), Plotting_Panel.Height)
                                Next
    
    
                            ElseIf Sweep60 = True Then
                                Dim Minor_gridFactor As Single = Plotting_Panel.Width / (5 * 5)
                                Dim Minor_gridPen As New Pen(Color.LightGray, 1)
                                Dim i As Double
                                mygraphics = Graphics.FromImage(Plotting_Signal)
                                For i = 0 To Plotting_Panel.Width Step Minor_gridFactor
                                    mygraphics.DrawLine(Minor_gridPen, CInt(i), 0, CInt(i), Plotting_Panel.Height)
                                Next
    
                            End If
                        End If
                        ''''For Majjor Grid
                        If Major_grid = True Then
    
                            Select Case True
                                Case Sweep7_5
                                    mygraphics = Graphics.FromImage(Plotting_Signal)
                                    Dim Major_gridFactor As Single = Plotting_Panel.Width / 40
                                    Dim Major_gridPen As New Pen(Color.Black, 1)
                                    Dim brush As New SolidBrush(Color.Black)
                                    Dim TimeFont As New Font("Arial", 13)
                                    Dim i As Double
                                    For i = 0 To Plotting_Panel.Width Step Major_gridFactor
                                        mygraphics.DrawLine(Major_gridPen, CInt(i), 0, CInt(i), Plotting_Panel.Height)
                                        second = second + 1
                                        mygraphics.DrawString(TimeDisplay(second), TimeFont, brush, (i + 1), (Plotting_Panel.Height - 50))
                                    Next
    
                                Case Sweep15
                                    mygraphics = Graphics.FromImage(Plotting_Signal)
                                    Dim Major_gridFactor As Single = Plotting_Panel.Width / 20
                                    Dim Major_gridPen As New Pen(Color.Black, 1)
                                    Dim brush As New SolidBrush(Color.Black)
                                    Dim TimeFont As New Font("Arial", 13)
    
                                    Dim i As Double
    
                                    For i = 0 To Plotting_Panel.Width Step Major_gridFactor
                                        mygraphics.DrawLine(Major_gridPen, CInt(i), 0, CInt(i), Plotting_Panel.Height)
                                        second = second + 1
                                        mygraphics.DrawString(TimeDisplay(second), TimeFont, brush, (i + 1), (Plotting_Panel.Height - 50))
                                    Next
    
                                Case Sweep30
                                    mygraphics = Graphics.FromImage(Plotting_Signal)
                                    Dim Major_gridFactor As Single = Plotting_Panel.Width / 10
                                    Dim Major_gridPen As New Pen(Color.Black, 1)
                                    Dim brush As New SolidBrush(Color.Black)
                                    Dim TimeFont As New Font("Arial", 13)
    
                                    Dim i As Double
                                    For i = 0 To Plotting_Panel.Width Step Major_gridFactor
                                        mygraphics.DrawLine(Major_gridPen, CInt(i), 0, CInt(i), Plotting_Panel.Height)
                                        second = second + 1
                                        mygraphics.DrawString(TimeDisplay(second), TimeFont, brush, (i + 1), (Plotting_Panel.Height - 50))
                                    Next
    
                                Case Sweep60
                                    mygraphics = Graphics.FromImage(Plotting_Signal)
                                    Dim Major_gridFactor As Single = Plotting_Panel.Width / 5
                                    Dim Major_gridPen As New Pen(Color.Black, 1)
                                    Dim brush As New SolidBrush(Color.Black)
                                    Dim TimeFont As New Font("Arial", 13)
                                    Dim i As Double
                                    For i = 0 To Plotting_Panel.Width Step Major_gridFactor
                                        mygraphics.DrawLine(Major_gridPen, CInt(i), 0, CInt(i), Plotting_Panel.Height)
                                        second = second + 1
                                        mygraphics.DrawString(TimeDisplay(second), TimeFont, brush, (i + 1), (Plotting_Panel.Height - 50))
                                    Next
    
                            End Select
                        End If
    
    
                    End If
                Loop
            Loop While running
            Me.Invoke(Sub() Me.Close())  'allow the form to close now
        End Sub
    
        Private Sub DrawGraph2(XVALUE1 As Integer)
    
    
            For sample = 0 To gMAX_SAMPLES - 1 ' no. of data values
                Plot_channel = Main_Panel_Channels_To_Display
                For channel = 0 To Plot_channel - 1 ' no. of lines to display
                                           // data processing to obtain final value  for filter buffer                                      
    
                    mygraphics = Graphics.FromImage(Plotting_Signal)
                    mygraphics.PageUnit = GraphicsUnit.Pixel
                    mygraphics.PageScale = 1
                    mygraphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
                    mygraphics.ScaleTransform(1, 1)
    
                    Ch1_y2 = Intfilterbuffer(sample, channel)
    
                    If Ch1_y2 > (Deflection * Pixels_Per_MM) Then
                        Ch1_y2 = Deflection * Pixels_Per_MM
                    ElseIf Ch1_y2 < (-1 * (Deflection * Pixels_Per_MM)) Then
                        Ch1_y2 = (Deflection * Pixels_Per_MM) * -1
                    End If
    
                    O1currentX = O1lastX + Sweep_factor
                    Ch1_y2 = Ch1_y2 + (channel + 1) * Channel_Area
    
                    p2.Color = panel1.Controls("Label" & (channel + 2).ToString).ForeColor
                    mygraphics.DrawLine(p2, O1lastX, Ch1_y1(channel), O1currentX, Ch1_y2)
    
                    Ch1_y1(channel) = Ch1_y2
                    'Me.Invoke(Sub()
                    '              Using gp As Graphics = Plotting_Panel.CreateGraphics
                    '                  gp.DrawImage(Plotting_Signal, 0, 0)
                    '              End Using
                    '          End Sub)
    
                Next
                O1lastX = O1currentX
                If O1lastX >= Plotting_Panel.Width Then
                    O1currentX = 0
                    O1lastX = 0
                    mygraphics.Clear(Color.LightYellow)
                    'Plotting_Signal.Dispose()
                    'Plotting_Signal = New Bitmap(Plotting_Panel.Width, Plotting_Panel.Height)
    
                    Plotting_Panel.Invalidate()
                End If
            Next
    
            If transmission = "a" Then
    
                Plot_Signal = True
    
                'Using gp As Graphics = Plotting_Panel.CreateGraphics
                '    gp.DrawImage(Plotting_Signal, 0, 0)
                'End Using
    
            End If
    
        End Sub
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  28. #28

    Thread Starter
    Member
    Join Date
    Jan 2018
    Posts
    39

    Re: How to Handle Serial data event and new frame event using Aforge library at same

    Hello Passel & dbasnett,

    I was able to solve my problem by changing my data processing code which was happening before plotting.
    Now both UI and signal plotting is real time.

    thank you for suggestions which helped me resolve my issue.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width