none
Application.DoEvents slows the vb.net app down? RRS feed

  • Question

  • I'm receiving continuous data from serialport, then clen thtis data from markers then add pace every 2 chars and reverse it, then add it to listview. So while i'm receiving one or two message with 10ms delay from serial, my listview doesnt lag, but when more then 2 messages, my UI starting lagging. I'm really realy confused with backroundworker and background threads, so i'm using DoEvents. The problem is that i actully dont know what slows down my app, is it DoEvetns or some opertions?

    Imports System
    Imports System.IO.Ports
    Imports System.IO
    Imports System.Text
    Imports System.Threading
    Imports System.Text.RegularExpressions
    
    Public Class Form1
        Dim What_to_do_idx As Byte = 0
        Dim data As String
        Dim dlc As String
        Dim can_id As String
        Dim CanMessage As String
        Dim uart_in As String
        Dim inputData As Byte
        Dim receivedData As String = ""
        Dim bytestosend(1) As Byte
        Dim count As Long = 1
        Dim timer_count As Integer
        Dim first_msg As Byte
        Dim asciival As String
        Private filter As String
        Private readBuffer As String = String.Empty
        Private Bytenumber As Integer
        Private ByteToRead As Integer
        Private byteEnd(2) As Char
        Private comOpen As Boolean
        Dim get_buffer As New StringBuilder
        Dim gatetimer As Byte = 0
        Dim watch As Stopwatch
        Private m_sSearchString As String
        Dim checklvvalue As Byte = 0
        Dim GetValueFromlv2Row As String
        Dim count_for_rx As Long
    
      Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            'stop the timer (stops this function being called while it is still working
            Timer1.Enabled = False
    
    
            'Timer2.Enabled = True
    
            ' get any new data and add the the global variable receivedData
            receivedData = ReceiveSerialData()
    
            'If receivedData contains a "<" and a ">" then we have data
            If ((receivedData.Contains("<") And receivedData.Contains(">"))) Then
                'RichTextBox2.Text = receivedData
                '    If Len(receivedData) = 28 Then
    
                parseData()
                '  parseData()
    
                ' End If
    
            End If
    
            ' restart the timer
            ' Timer2.Enabled = False
    
            Timer1.Enabled = True
        End Sub
        Function ReceiveSerialData() As String
            ' Timer2.Enabled = True
            Dim Incoming As String
            Try
    
                Incoming = spObj.ReadExisting()
                If Incoming Is Nothing Then
                    Return "nothing" & vbCrLf
                Else
                    Return Incoming
                End If
            Catch ex As TimeoutException
                Return "Error: Serial Port read timed out."
            End Try
        End Function
        Function parseData()
    
    
            ' uses the global variable receivedData
            Dim pos1 As Integer
            Dim pos2 As Integer
            Dim length As Integer
            Dim newCommand As String
            Dim done As Boolean = False
            Dim count As Integer = 0
    
            While (Not done)
    
                pos1 = receivedData.IndexOf("<") + 1
                pos2 = receivedData.IndexOf(">") + 1
    
                'occasionally we may not get complete data and the end marker will be in front of the start marker
                ' for exampe "55><T0056><"
                ' if pos2 < pos1 then remove the first part of the string from receivedData
                If (pos2 < pos1) Then
                    receivedData = Microsoft.VisualBasic.Mid(receivedData, pos2 + 1)
                    pos1 = receivedData.IndexOf("<") + 1
                    pos2 = receivedData.IndexOf(">") + 1
                End If
    
                If (pos1 = 0 Or pos2 = 0) Then
                    ' we do not have both start and end markers and we are done
                    done = True
    
                Else
                    ' we have both start and end markers
    
                    length = pos2 - pos1 + 1
                    If (length > 0) Then
                        'remove the start and end markers from the command
                        newCommand = Mid(receivedData, pos1 + 1, length - 2)
    
                        ' show the command in the text box
                        ' RichTextBox1.Text = ""
                        'RichTextBox1.AppendText(newCommand & vbCrLf)
                        get_buffer.Remove(0, get_buffer.Length)
                        get_buffer.Append(newCommand & vbCrLf)
    
                        'remove the command from receivedData
                        'receivedData = Mid(receivedData, pos2 + 1)
                        'RichTextBox1.Text &= receivedData
    
    
                        uart_in = get_buffer.ToString
                        If uart_in.Length <> 28 Then Exit Function
    
                        dlc = Mid(uart_in, 10, 1)
                        Try
                            data = uart_in.Substring(26 - (dlc * 2))
                        Catch ex As Exception When TypeOf ex Is ArgumentOutOfRangeException OrElse TypeOf ex Is System.InvalidCastException
    
                            Exit Function
                        End Try
                        can_id = Mid(uart_in, 6, 3) 'extracting and id
    
                        'If data.Length > 26 Then Exit Function
                        ' data = ReverseString(data)
                        'data = Reverse(data)
    
                        data = String.Join("", Regex.Matches(data, ".{2}").Cast(Of Match).Reverse().Select(Function(M As Match) M.Value).ToArray())
    
                        hex2ascii(data)
                        data = data.InsertEveryNthChar(" ", 2)
                        '   RichTextBox4.AppendText(can_id & vbTab & dlc & vbTab & data & vbTab & asciival & vbCrLf)
                        'anotherlv()
                        ' Button5_Click(Nothing, Nothing)
    
                        Dim founditem As ListViewItem = ListView1.FindItemWithText(can_id)
                        If Not (founditem Is Nothing) Then
                            founditem.SubItems(0).Text = can_id
                            founditem.SubItems(1).Text = dlc
                            If founditem.SubItems(2).Text <> data And data.Length <= 24 Then
                                founditem.SubItems(2).Text = data
                                'founditem.SubItems(2).BackColor = Color.LightGray
                                first_msg = 0
                            Else
                                first_msg += 1
                                If first_msg = 1 Then
                                    founditem.SubItems(2).BackColor = Color.White
    
                                End If
                            End If
                            If founditem.SubItems(4).Text = 1 Then
                                inputData = 1
                                founditem.SubItems(3).Text = timer_count * 2
                            Else
    
    
                            End If
                            founditem.SubItems(4).Text = founditem.SubItems(4).Text + 1
                            founditem.SubItems(5).Text = asciival
                            'ListView1.Update()
                            Application.DoEvents()
                            first_msg = 0
                        Else
                             Application.DoEvents()
                            Dim lvi As New ListViewItem(can_id)
                            lvi.UseItemStyleForSubItems = False
                            lvi.SubItems.Add(dlc)
                            lvi.SubItems.Add(data)
                            lvi.SubItems.Add(What_to_do_idx)
                            lvi.SubItems.Add(count)
                            lvi.SubItems.Add(asciival)
                            ListView1.Items.Add(lvi)
    
                        End If
                    End If ' (length > 0) 
                End If '(pos1 = 0 Or pos2 = 0)
            End While
            first_msg = 0
    
        End Function

    Friday, September 22, 2017 9:45 AM

All replies

  • The problem is that i actully dont know what slows down my app, is it DoEvetns or some opertions?

    ReadExisting does not time out, so there is no need for that Try/Catch. If you are concerned about re-entrancy in the timer tick event, then use a flag instead of stopping and starting the timer:

        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Static Processing As Boolean = False
            If Not Processing Then
                Processing = True
                ...
                Processing = False
            End If
        End Sub
    
    10ms timer ticks are far too short.  It won't speed up your programme to use a short timer tick.  In fact, it will slow processing down, because the system will be spending its time responding to timer ticks instead of getting on with the processing. Your program speed is going to be controlled by the baud rate of the serial port.     The only time you will notice any delay due to a long timer tick is at the very end of the message - you need to decide what maximum delay you can accept for that.   I doubt that anything less than 100ms would be required, but I would test it out to 250ms.  I can't see that there is any reason for DoEvents at all - perhaps the 10ms timer tick was loading the system so much that it seemed unresponsive.  What happens if you remove the DoEvents?  The Try/Catch in the parsing should be replaced by specific validation of the data item - string length and Integer.TryParse.
    Friday, September 22, 2017 11:12 AM
  • A windows forms timer will most likely not run at 10 ms intervals. If you add a stopwatch you can see what the actual time interval is and it is most likely not less than 15ms or more like 30 ms. Plus the time interval varies based on other system activity. Say you run 30 ms you will see some intervals at 15ms and another at 45 ms and then 15 such that the long count averages near the set time interval.

    When using a timer it is the same as having a do events as the execution is returned to the system after each timer tick. So yes another doevents  may slow things down and for sure it wont help anything.

    I agree with Acamar's guess that the parseData mi9ght be slowing you down (besides just how long the serial data takes to acquire). Put a stopwatch around it and see. Your string functions like append can be very slow and could be a 10 ms delay alone.

    You need to test. Add a stopwatch so you can see the real times executing. YOu can not go by the timer interval. Then comment out some of the code functions and run. See if the stopwatch time interval changes much between removing/added this and that. Take out the doevents and see if the timing changes etc.

    This thread has a timing example using a stopwatch. This thread is complex it draws a graph of the times etc. All you need to do is add in the stopwatch control like in this thread.

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/7d3860d9-5dc8-4b86-a258-85cbfc567ed0/saving-1-image-every-16-millisecond-in-vb?forum=vbgeneral

    PS Armin gave us a faster way to add strings in this thread. Much faster than append or join. Check it out if you determine your time is being used up in your parsedata sub.

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/7e3e9c72-682d-4b4e-9170-bacd341673c7/best-way-to-convert-a-string-of-integers-to-an-array?forum=vbgeneral

    PSS Sorry, Armins example is for splitting strings. But it will give you some good info on how long some string functions take. And on setting up a timing test with a stopwatch.

    Friday, September 22, 2017 12:08 PM
  • I don't know of any reason to use DoEvents in VB.Net and it seems likely that any attempt to use it for something like this will fail.

    Have you read Serial Communications? You need to and study it too. That sample uses three threads.

    Also see Serial communication in Win32; you should rely on nobugz's expertise. He seems to say it is possible to use only one thread but you must understand what they are saying.

    Trying to synchronize your program with the hardware using a timer is futile. It won't work. Serial communications is complicated. It will defeat you if you try to make it easy.

    Try/Catch is always useful if a method ever throws an exception. I have never heard of a performance problem caused by Try/Catch.



    Sam Hobbs
    SimpleSamples.Info



    Saturday, September 23, 2017 12:45 AM
  • Trying to synchronize your program with the hardware using a timer is futile. It won't work. Serial communications is complicated. It will defeat you if you try to make it easy.

    Not so.    Using a timer tick event to regularly check the status of the buffer is a perfectly valid way to use the serial port.

    Saturday, September 23, 2017 12:56 AM
  • Using a timer tick event to regularly check the status of the buffer is a perfectly valid way to use the serial port.

    I have already posted a link to the authoritive MSDN article. Do you know of anything authoritive saying that a timer is a good solution for serial communications?


    Sam Hobbs
    SimpleSamples.Info

    Saturday, September 23, 2017 1:59 AM
  • I have already posted a link to the authoritive MSDN article. Do you know of anything authoritive saying that a timer is a good solution for serial communications?

    Please do not rewrite my comment - I said that the technique was perfectly valid.  Your comment included "futile", "won't work" and "will defeat you", and none of that is correct. 

    If you want to discuss good or bad you should start by stating your criteria.

    Saturday, September 23, 2017 2:09 AM
  • Please do not rewrite my comment - I said that the technique was perfectly valid.  Your comment included "futile", "won't work" and "will defeat you", and none of that is correct. 

    This is becoming argumentative. The best solution is to post relevant and authoritive facts. I have done that.


    Sam Hobbs
    SimpleSamples.Info

    Saturday, September 23, 2017 2:33 AM
  • Please do not rewrite my comment

    I assumed that "rewrite" means "mis-quote". I apologize if I misunderstood.

    I said that the technique was perfectly valid.  Your comment included "futile", "won't work" and "will defeat you", and none of that is correct.

    I apologize if that felt like a personal attack, I did not intend it to be. Yes I used strong words and if I am incorrect then prove me wrong with facts.



    Sam Hobbs
    SimpleSamples.Info

    Saturday, September 23, 2017 4:01 AM
  • When i removed doevents and inreased timer interval, app became faster a lot. But count column is not smooth, it add "how moch messages of the same id we received" it jumps in a huge range from 0 to 20 from 40 to 60 etc. not smoothly adding by 1. And UI freezes a little bit when im dragging a form. BUt if its hard to fix, so im okay with that. 
    • Edited by I.newbie Monday, September 25, 2017 9:06 AM
    Monday, September 25, 2017 8:18 AM
  • @TommytwoRain

    StopWatch shows me diffrent range everytime, it shows me range from 10ms to 20ms, every time diffrent, its how much parsedata takes time
    Monday, September 25, 2017 8:20 AM
  • When i removed doevents and inreased timer interval, app became faster a lot. But count column is not smooth

    That is to be expected.   Serial data transmission does not occur smoothly, and the time taken to parse messages will vary a lot depending on which part of the message you are looking at and how much data was received in the interval.  If you are monitoring the processing time it will vary a lot.  But the only thing that really matters is how long after the message completes before you get to see the parsed result: that depends nearly entirely on the timer tick interval, and it's unlikely that any reasonable interval will be noticeable.

    Monday, September 25, 2017 9:11 AM
  • @TommytwoRain

    StopWatch shows me diffrent range everytime, it shows me range from 10ms to 20ms, every time diffrent, its how much parsedata takes time

    Yes. Well that's what we are talking about.

    First of all if you look at the first link I gave look at the graph of the time interval. The windows form timer will vary the actual interval for each tick. But it will try to average the interval over several ticks. So if you have the windows form timer interval set on 30 ms you might see an interval of 40 ms followed by 20 thus avg 30 ms.

    And then like Acamar says the amount of data varies so the time to process it varies.

    I cant test what you are doing as I don't have the serial data to process.

    That does not mean you cant make it work. Just that you have to have enough time slack in the overall time interval process to catch up and process the data with each tick.

    PS Look at the example I gave in my frirst link. The times given measured by the stop watch is an average time over say 500 ms. And the average time display on the screen is only shown every 20 ticks or so. The time is changing so fast you cant see it unless you only show it on the screen every second or so.

    PSS

    Acamar knows this a lot better than I so I wont say much more.

    However maybe look at this like filling a bucket with water from a hose. First of all the amount of water coming from the hose, the serial data, varies in rate from 1 liter per second to 10 liters per second. And then the rate you can empty the bucket varies based on other things you are doing and the bucket is emptied at a varieable rate (the parse data sub).

    So the whole trick is to have a big enough bucket to catch all the water coming from the hose and then empty the bucket fast enough not to miss any data. So if you have two buckets, one gets filled while one gets emptied. As long as the buckets (timer interval) are large enough it will work?


    Monday, September 25, 2017 12:12 PM
  • Here is a shell that demonstrates another (better?) way to handle serial communications.  It has served me well over the years because it does not use the UI thread, and therefore doesn't need to use DoEvents.  What would be required to use this is to figure out the code that goes in the Protocol method.  Good luck.

        Private isRun As New Threading.ManualResetEvent(False)
        Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
    
            'this thread reads bytes and adds them to the buffer
            rcvdThrd = New Threading.Thread(AddressOf Receive)
            rcvdThrd.IsBackground = True
    
            'this thread examines the buffer to see if a 
            'complete message, as defined by the protocol, is available
            procprotoThrd = New Threading.Thread(AddressOf Protocol)
            procprotoThrd.IsBackground = True
    
            isRun.Set() 'we are running
            procprotoThrd.Start()
            rcvdThrd.Start()
        End Sub
    
        Private WithEvents sp As New SerialPort
    
        Private Sub sp_DataReceived(sender As Object, _
                                    e As SerialDataReceivedEventArgs) _
                                Handles sp.DataReceived
            rcvd.Set() 'read the bytes, see method Receive
        End Sub
    
        Private Sub sp_ErrorReceived(sender As Object, _
                                     e As SerialErrorReceivedEventArgs) Handles sp.ErrorReceived
            Debug.WriteLine(e.EventType.ToString)
        End Sub
    
        Private Sub sp_PinChanged(sender As Object, _
                                  e As SerialPinChangedEventArgs) Handles sp.PinChanged
            Debug.WriteLine(e.EventType.ToString)
        End Sub
    
        Private rcvd As New Threading.AutoResetEvent(False)
        Private rcvdThrd As Threading.Thread
    
        Private Sub Receive()
            Do
                If sp.IsOpen Then 'is port open
                    Dim numb As Integer = sp.BytesToRead 'number of bytes to read
                    If numb > 0 Then
                        Dim temp(numb - 1) As Byte 'create a temporary buffer
                        Try
                            numb = sp.Read(temp, 0, numb) 'read the bytes
                            If numb <> temp.Length Then
                                Array.Resize(temp, numb)
                            End If
                            'add temp buffer to public buffer
                            Threading.Monitor.Enter(bufLock)
                            buf.AddRange(temp)
                            Threading.Monitor.Exit(bufLock)
                            procproto.Set() 'check for possible message, see method Protocol
                        Catch ex As Exception
                            'fix error handler
                        End Try
                    End If
                End If
                rcvd.WaitOne() 'wait for event handler to fire
            Loop While isRun.WaitOne(0)
        End Sub
    
        Private buf As New List(Of Byte)
        Private bufLock As New Object
    
        Private procproto As New Threading.AutoResetEvent(False)
        Private procprotoThrd As Threading.Thread
    
        Private Sub Protocol()
            Do
                If buf.Count > 0 Then 'SOME data present
                    'is it a complete message as defined by our protocol?
                    'if so process it
                    'remember that buf could be accessed from the receive thread, 
                    'so use a technique that is similar to how the bytes were added
    
    
                End If
                procproto.WaitOne() 'wait for signal to proccess next potential message
            Loop While isRun.WaitOne(0)
        End Sub


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.


    • Edited by dbasnett Monday, September 25, 2017 1:51 PM
    Monday, September 25, 2017 1:49 PM
  • Here is a shell that demonstrates another (better?) way to handle serial communications.  It has served me well over the years because it does not use the UI thread, and therefore doesn't need to use DoEvents.

    That code is not suitable for OP's application.   Because the data is continuous, the messages are brief, missed messages are ignored and GUI updating is the critical timing factor, the serial port data should be processed in the GUI thread to maintain control over the parsing and, in particularly, to avoid parsing of messages that have already been superseded before the parser gets to them. That cannot be done easily if the message is received in its own thread.   DoEvents was never required, as OP has now confirmed.

    Tuesday, September 26, 2017 7:35 AM
  • Here is a shell that demonstrates another (better?) way to handle serial communications.  It has served me well over the years because it does not use the UI thread, and therefore doesn't need to use DoEvents.

    That code is not suitable for OP's application.   Because the data is continuous, the messages are brief, missed messages are ignored and GUI updating is the critical timing factor, the serial port data should be processed in the GUI thread to maintain control over the parsing and, in particularly, to avoid parsing of messages that have already been superseded before the parser gets to them. That cannot be done easily if the message is received in its own thread.   DoEvents was never required, as OP has now confirmed.

    It isn't clear to me what the OP is actually doing, or what the protocol is.

    I have used the code I posted to receive data from a serial port at speeds in excess of 1Mbps(bluetooth serial), so if the OP's code can work using a timer then it will work with the code I posted.  The trick will be in the method named Protocol and getting the data to the UI.  The data received is in the correct order in the variable named buf.

    Perhaps I missed your point.  Did you test what I posted? 


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.


    • Edited by dbasnett Tuesday, September 26, 2017 2:25 PM
    Tuesday, September 26, 2017 2:22 PM
  • I have used the code I posted to receive data from a serial port at speeds in excess of 1Mbps(bluetooth serial), so if the OP's code can work using a timer then it will work with the code I posted. 

    There's nothing wrong with that solution, it's just not appropriate for OP's task.  The data rate is not high, but the data stream is continuous and the GUI updating is extensive, with later messages obsoleting earlier ones and making them redundant.  You can see that in the history of the project.  OP needs to ensure there is no unnecessary parsing and GUI updating gets priority. For instance, GUI updating must always be allowed to complete with the existing information, even if new information arrives in the meantime. Only the message current at GUI completion should be parsed and used.  That sort of management is easier if the receiving is in the GUI thread.

    Tuesday, September 26, 2017 11:51 PM
  • I have used the code I posted to receive data from a serial port at speeds in excess of 1Mbps(bluetooth serial), so if the OP's code can work using a timer then it will work with the code I posted. 

    There's nothing wrong with that solution, it's just not appropriate for OP's task.  The data rate is not high, but the data stream is continuous and the GUI updating is extensive, with later messages obsoleting earlier ones and making them redundant.  You can see that in the history of the project.  OP needs to ensure there is no unnecessary parsing and GUI updating gets priority. For instance, GUI updating must always be allowed to complete with the existing information, even if new information arrives in the meantime. Only the message current at GUI completion should be parsed and used.  That sort of management is easier if the receiving is in the GUI thread.

    @Acamar

    This is the problem with lags: dragging form, and not smooth UI - https://youtu.be/ez34I5Uh3R8. But as i said that level of lags i accept. Problem comes when im trying to update another controls with another timer's code while im getting data from serial and doing parsing. For example: 

       Private Sub Button8_Click(sender As Object, e As EventArgs) Handles Button8.Click
            If ListViewExtended1.Items.Count >= 0 Then
                timer_firstROW.Enabled = True
            Else
                timer_firstROW.Enabled = False
            End If
       End sub
    
     Private Sub Timer4_Tick(sender As Object, e As EventArgs) Handles timer_firstROW.Tick
            timer_firstROW.Interval = ListViewExtended1.Items(0).SubItems(3).Text
            count_for_rx = ListViewExtended1.Items(0).SubItems(4).Text + 1
            ListViewExtended1.Items(0).SubItems(4).Text = count_for_rx
            GetValueFromlv2Row = "434D4431" & ListViewExtended1.Items(0).SubItems(0).Text & ListViewExtended1.Items(0).SubItems(1).Text & ListViewExtended1.Items(0).SubItems(2).Text.Replace(" ", "")
            Dim count As Short
            Dim bytestosend(0) As Byte
            For count = 1 To GetValueFromlv2Row.Length Step 2  'For count = 249 To Text4.Text * 2 Step 8 page 32
                bytestosend(0) = CLng("&H" & Mid(GetValueFromlv2Row, count, 2))
                spObj.Write(bytestosend, 0, bytestosend.Length)
            Next
            spObj.Write(Microsoft.VisualBasic.ControlChars.Cr)
        End Sub

    Here i send a data as serial from LvExtended1, if interval lower then 20, i got more lags. And i want to send 3 or more data at the same time with timers(i'm using timers becuse i need to send messages with diffrent interval in ms). Maybe there are another more experinced way to do that, or am i doing something wrong with timers


    • Edited by I.newbie Wednesday, September 27, 2017 7:19 AM
    Wednesday, September 27, 2017 7:18 AM
  • But as i said that level of lags i accept. Problem comes when im trying to update another controls with another timer's code while im getting data from serial and doing parsing.

    Do not user timer intervals that short - it will create lags.    You can't make the program run faster just by speeding up the timers - you have to make the code more efficient, and in particular you have to implement code that skips over processing that has been made redundant. I can't see from that code that multiple timers are required, but you should not have more than one if possible.   What are the intervals for the messages?

    Your code that accesses the listview items will be very slow.  The preferable arrangement is that the listview is used to display a list of objects that is maintained separately.   Code such as
            GetValueFromlv2Row = "434D4431" & ListViewExtended1.Items(0).SubItems(0).Text & ListViewExtended1.Items(0).SubItems(1).Text & ListViewExtended1.Items(0).SubItems(2).Text.Replace(" ", "")

    should be accessing properties of the object that is represented by that row, not the listview row and subitems themselves. Those objects are created as the data becomes available, but the listview is updated only as required - the user's need to see that data is not as important as the need to have it available for the message.   Getting that data from the object instead of the listview also means that formatting etc can be done in the object property set code, so that code executed during the timing-critical processing is at an absolute minimum.  For instance, you sending code requires conversions for Long and hex - that is exactly the sort of conversion that should occur in the object initialisation or the object property set, not in the timer tick event. 

    You should also confirm that you really need a listview - if a list with strings formatted into columns would do as well, that would considerably simplify the code.  That is the sort of area you need to look for speed - not in speeding up the timers.

    Wednesday, September 27, 2017 7:59 AM
  • But as i said that level of lags i accept. Problem comes when im trying to update another controls with another timer's code while im getting data from serial and doing parsing.

    Do not user timer intervals that short - it will create lags.    You can't make the program run faster just by speeding up the timers - you have to make the code more efficient, and in particular you have to implement code that skips over processing that has been made redundant. I can't see from that code that multiple timers are required, but you should not have more than one if possible.   What are the intervals for the messages?

    Your code that accesses the listview items will be very slow.  The preferable arrangement is that the listview is used to display a list of objects that is maintained separately.   Code such as
            GetValueFromlv2Row = "434D4431" & ListViewExtended1.Items(0).SubItems(0).Text & ListViewExtended1.Items(0).SubItems(1).Text & ListViewExtended1.Items(0).SubItems(2).Text.Replace(" ", "")

    should be accessing properties of the object that is represented by that row, not the listview row and subitems themselves. Those objects are created as the data becomes available, but the listview is updated only as required - the user's need to see that data is not as important as the need to have it available for the message.   Getting that data from the object instead of the listview also means that formatting etc can be done in the object property set code, so that code executed during the timing-critical processing is at an absolute minimum.  For instance, you sending code requires conversions for Long and hex - that is exactly the sort of conversion that should occur in the object initialisation or the object property set, not in the timer tick event. 

    You should also confirm that you really need a listview - if a list with strings formatted into columns would do as well, that would considerably simplify the code.  That is the sort of area you need to look for speed - not in speeding up the timers.

    With extra timers i want to send continous data too, same as i get it. What was my plann: Create lestiview where user Put all info: id, length of message, period in ms, data. Then user clicks "Send all" button, and all rows that he added into listview, will be read by timers, timer1 will send raw 1, timer2 will send raw2,timer3 will send raw3 etc. It will make possible send 3 messages 1 by 1. Also i chose timer becaouse i dont know how to regulate delay between messages. Those delays can vary from 10ms to 1sec all depens on value that user wrote in 
     timer_firstROW.Interval = ListViewExtended1.Items(0).SubItems(3).Text
    . For exmaple i need send message continously every 50ms, so n my mind  came only timer.interval that can handle it? but now i see that then shorter interval then i get more lags. How should i be? Thanks for keep helping with my first serial project, Acamar


    • Edited by I.newbie Wednesday, September 27, 2017 9:02 AM
    Wednesday, September 27, 2017 8:43 AM
  • For exmaple i need send message continously every 50ms, so n my mind  came only timer.interval that can handle it? but now i see that then shorter interval then i get more lags.

    That means that my comment re using objects for your data, and only using the listview (or something simpler) to display information for the user, is applicable.    You need to prepare objects that are designed for the purpose of sending the required message, but which also support a display format that can be used in the listview.  That will overcome most of the speed problem. 

    You need to start by confirming that you can actually transmit a message in 50ms.   A baud rate of 2400, for instance, corresponds to about 4ms per byte.  So you will get about 12 characters in 50ms, assuming everything works perfectly.  You can calculate the available characters per 50ms at other baud rates. That's the rate that the data will go at, regardless of how often the timer ticks.   You haven't indicated what baud rate you are using, but any assumption that a message is going to take a particular maximum time is risky.  Similarly, any assumption that there is some predictable connection between the timer tick and the time at which the message is actually sent is going to be wrong.

    Does "send message continously every 50ms," mean send continuously or send every 50ms - they aren't the same thing?  I still can't see that there is a need for multiple timers - it seems that you want to send 3 messages every 50ms, so one timer would be sufficient. 

    But for sending, the timer interval doesn't affect performance IF you ensure that the message can be sent within the timer interval. You should be checking the send buffer status before sending each message, and ensure that it is not steadily increasing, indicating that you are providing data more quickly than it can be sent.

    If you mean that you want to send continuously then your timer tick interval can be anything you like, but it should be much more than 50ms.   That will mean that you need to load the send buffer with multiple messages at each tick.  Then check the send buffer at each tick, and only load it when it gets low.

    If you do that correctly the lag in the system will not be due to the serial port sending.  It will be due to inefficiencies in your code, such as trying to parse lines in a listview when the data should be already prepared to send in the objects that are the source of your data.

    Wednesday, September 27, 2017 10:08 AM
  • I have used the code I posted to receive data from a serial port at speeds in excess of 1Mbps(bluetooth serial), so if the OP's code can work using a timer then it will work with the code I posted. 

    There's nothing wrong with that solution, it's just not appropriate for OP's task.  The data rate is not high, but the data stream is continuous and the GUI updating is extensive, with later messages obsoleting earlier ones and making them redundant.  You can see that in the history of the project.  OP needs to ensure there is no unnecessary parsing and GUI updating gets priority. For instance, GUI updating must always be allowed to complete with the existing information, even if new information arrives in the meantime. Only the message current at GUI completion should be parsed and used.  That sort of management is easier if the receiving is in the GUI thread.

    Without a clear statement of what the OP is doing it is hard to know. 

    My experience has been to

    • NOT manipulate the serial port from the UI, except maybe opening / closing
    • use the DataReceived event handler (and the other serial port handlers)
    • craft any UI interaction so that it occurs only when needed

    I have two setups that I use to test.

    • PC serialport ---> LoopBack
    • PC serialport ---> Other PC serialport

    In the code below I used the first.  What I added was the code to open/close the port, some code to send data, and a crude protocol definition. My UI interaction is limited to message count, last message size, and messages received per second.

    With a message size of 32 bytes I was able to send more than 200 message per second, and receive more than 200 messages per second.  That is over 400 messages per second total.  As the message size increases the rate decreases and vice versa.  From watching the OPs video I can't tell what message rate they have.  As said earlier there is not a clear statement of what the OP is doing.

    At no time during the testing did the UI freeze or lag.  So we disagree about how best to interact with the serial port, and obviously our experiences have led to this. 

    Imports System.IO.Ports
    
    Public Class Form1
    
        Private isRun As New Threading.ManualResetEvent(False)
    
        Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
            isRun.Reset()
            Threading.Thread.Sleep(100)
            rcvd.Set()
            Threading.Thread.Sleep(100)
            procproto.Set()
            Threading.Thread.Sleep(100)
            If sp.IsOpen Then sp.Close()
            Threading.Thread.Sleep(100)
        End Sub
    
        Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
    
            'this thread reads bytes and adds them to the buffer
            rcvdThrd = New Threading.Thread(AddressOf Receive)
            rcvdThrd.IsBackground = True
    
            'this thread examines the buffer to see if a 
            'complete message, as defined by the protocol, is available
            procprotoThrd = New Threading.Thread(AddressOf Protocol)
            procprotoThrd.IsBackground = True
    
            isRun.Set() 'we are running
            procprotoThrd.Start()
            rcvdThrd.Start()
            Try
                sp.PortName = "COM1"
                sp.BaudRate = 115200
                sp.DataBits = 8
                sp.Parity = Parity.None
                sp.StopBits = StopBits.One
    
                sp.Open()
    
                SendDataCont()
            Catch ex As Exception
                Stop
            End Try
    
        End Sub
    
        Const sbufSZ As Integer = 32 '  8 ' 16
        Private Shared prng As New Random
        Private Sub SendDataCont()
            Dim t As Task = Task.Run(Sub()
                                         Do
                                             Dim sBuf(sbufSZ - 1) As Byte
                                             prng.NextBytes(sBuf)
                                             sp.Write(sBuf, 0, sBuf.Length)
                                             'Threading.Thread.Sleep(0)
                                         Loop While isRun.WaitOne(0)
                                     End Sub)
        End Sub
    
        Private WithEvents sp As New SerialPort
    
        Private Sub sp_DataReceived(sender As Object, _
                                    e As SerialDataReceivedEventArgs) _
                                Handles sp.DataReceived
            rcvd.Set() 'read the bytes, see method Receive
        End Sub
    
        Private Sub sp_ErrorReceived(sender As Object, _
                                     e As SerialErrorReceivedEventArgs) Handles sp.ErrorReceived
            Debug.WriteLine(e.EventType.ToString)
        End Sub
    
        Private Sub sp_PinChanged(sender As Object, _
                                  e As SerialPinChangedEventArgs) Handles sp.PinChanged
            Debug.WriteLine(e.EventType.ToString)
        End Sub
    
        Private rcvd As New Threading.AutoResetEvent(False)
        Private rcvdThrd As Threading.Thread
    
        Private Sub Receive()
            Do
                If sp.IsOpen Then 'is port open
                    Dim numb As Integer = sp.BytesToRead 'number of bytes to read
                    If numb > 0 Then
                        Dim temp(numb - 1) As Byte 'create a temporary buffer
                        Try
                            numb = sp.Read(temp, 0, numb) 'read the bytes
                            If numb <> temp.Length Then
                                Array.Resize(temp, numb)
                            End If
                            'add temp buffer to public buffer
                            Threading.Monitor.Enter(bufLock)
                            buf.AddRange(temp)
                            Threading.Monitor.Exit(bufLock)
                            procproto.Set() 'check for possible message, see method Protocol
                        Catch ex As Exception
                            'fix error handler
                        End Try
                    End If
                    rcvd.WaitOne() 'wait for event handler to fire
                End If
            Loop While isRun.WaitOne(0)
        End Sub
    
        Private buf As New List(Of Byte)
        Private bufLock As New Object
    
        Private procproto As New Threading.AutoResetEvent(False)
        Private procprotoThrd As Threading.Thread
    
        Private Sub Protocol()
            Dim ct As Integer = 0
            Dim stpw As Stopwatch = Stopwatch.StartNew
            Do
                If buf.Count > 0 Then 'SOME data present
                    'is it a complete message as defined by our protocol?
                    'if so process it
                    'remember that buf could be accessed from the receive thread, 
                    'so use a technique that is similar to how the bytes were added
                    If buf.Count >= sbufSZ Then
                        ct += 1
                        Threading.Monitor.Enter(bufLock)
                        Dim pbuf() As Byte = buf.ToArray
                        buf.Clear()
                        Threading.Monitor.Exit(bufLock)
                        Try
                            Me.Invoke(Sub()
                                          TextBox1.Text = String.Format("Msgs {0:n0}  {1:n0} {2:n0} ", ct, pbuf.Length, ct / stpw.Elapsed.TotalSeconds)
                                      End Sub)
                        Catch ex As Exception
    
                        End Try
                    End If
                End If
                procproto.WaitOne() 'wait for signal to proccess next potential message
            Loop While isRun.WaitOne(0)
        End Sub
    End Class
    


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.

    Wednesday, September 27, 2017 11:29 AM
  • At no time during the testing did the UI freeze or lag.

    There is a very clear statement available of what OP is doing - it has a long history.

    I don't understand why you would expect using a serial port in that manner to cause the UI to freeze or lag.   In exactly the same way that I wouldn't expect it to lag if it was driven from the UI using a timer interrupt.  OP's problem has nothing to do with the way that the serial port is being managed.   It is entirely to do with the use of inappropriate timer intervals.  It wouldn't matter what the code  in the timer was doing - setting the intervals to 10ms is going to create problems, as OP has now proven. 

    At no stage have I made comment about the best way to handle the serial port, and the thread should not be dragged off-topic into that discussion. 

    Wednesday, September 27, 2017 11:49 AM
  • At no time during the testing did the UI freeze or lag.

    There is a very clear statement available of what OP is doing - it has a long history.

    I don't understand why you would expect using a serial port in that manner to cause the UI to freeze or lag.   In exactly the same way that I wouldn't expect it to lag if it was driven from the UI using a timer interrupt.  OP's problem has nothing to do with the way that the serial port is being managed.   It is entirely to do with the use of inappropriate timer intervals.  It wouldn't matter what the code  in the timer was doing - setting the intervals to 10ms is going to create problems, as OP has now proven. 

    At no stage have I made comment about the best way to handle the serial port, and the thread should not be dragged off-topic into that discussion. 

    There is not what I would call a clear statement in this thread.  Clear to me is, at a minimum,

    • port setup (data rate, parity, etc)
    • protocol / message format
    • what the program does with the data

    Looking at the OP's code I see a serial port write occurring on the UI.  That might cause the UI issues.  As I have said my opinion is that manipulating the serial port from the UI is not a good thing.

    You have said "At no stage have I made comment about the best way to handle the serial port, " and "There's nothing wrong with that solution, it's just not appropriate for OP's task."

    So lets not get off-topic.  My opinion is that the approach is flawed and I don't have some information that you do.  Good luck to you and the OP.

    My start with VB was a serial port project.  Over the years I strove to find a solution that worked without reinventing some new way each time I dealt with the serial port.  It took some time to learn the nuances but this fundamentally is where I ended up.  The approach presented worked for everything from simple terminal interfaces to devices providing unsolicited status information.  One thing I learned was that mixing the UI, and in particular form timers, with the serial port affected both in ways that were not productive.

    Obviously your experience with the serial port is different than mine and lacking evidence to the contrary I can't say you are wrong.

    The following was tested with PC Serialport connected to loopback plug

    Imports System.IO.Ports
    
    Public Class Form1
    
        Private isRun As New Threading.ManualResetEvent(False)
    
        Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
            isRun.Reset()
            Threading.Thread.Sleep(100)
            rcvd.Set()
            Threading.Thread.Sleep(100)
            procproto.Set()
            Threading.Thread.Sleep(100)
            If sp.IsOpen Then sp.Close()
            Threading.Thread.Sleep(100)
        End Sub
    
        Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
    
            'this thread reads bytes and adds them to the buffer
            rcvdThrd = New Threading.Thread(AddressOf Receive)
            rcvdThrd.IsBackground = True
    
            'this thread examines the buffer to see if a 
            'complete message, as defined by the protocol, is available
            procprotoThrd = New Threading.Thread(AddressOf Protocol)
            procprotoThrd.IsBackground = True
    
            isRun.Set() 'we are running
            procprotoThrd.Start()
            rcvdThrd.Start()
            Try
                sp.PortName = "COM1"
                sp.BaudRate = 115200
                sp.DataBits = 8
                sp.Parity = Parity.None
                sp.StopBits = StopBits.One
                sp.Encoding = System.Text.Encoding.GetEncoding(28591)
                sp.Open()
    
                Dim dgvType As Type = DataGridView1.[GetType]()
                Dim pi As Reflection.PropertyInfo = dgvType.GetProperty("DoubleBuffered", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic)
                pi.SetValue(DataGridView1, True, Nothing)
                SendDataCont()
            Catch ex As Exception
                Stop
            End Try
    
        End Sub
    
        Private Shared prng As New Random
        Private Sub SendDataCont()
            '
            ' SIMULATE DEVICE
            '
            Dim t As Task = Task.Run(Sub()
                                         Dim ct As Integer = 1
                                         Do
                                             'simulated message from device
                                             Dim mess As String = String.Format("{0} This is a test  {1:n0}  ***  ", prng.Next(1, 11).ToString.PadLeft(4, "0"c), ct)
                                             sp.WriteLine(mess)
                                             ct += 1
                                         Loop While isRun.WaitOne(0)
                                     End Sub)
        End Sub
    
        Private WithEvents sp As New SerialPort
    
        Private Sub sp_DataReceived(sender As Object, _
                                    e As SerialDataReceivedEventArgs) _
                                Handles sp.DataReceived
            rcvd.Set() 'read the bytes, see method Receive
        End Sub
    
        Private Sub sp_ErrorReceived(sender As Object, _
                                     e As SerialErrorReceivedEventArgs) Handles sp.ErrorReceived
            Debug.WriteLine(e.EventType.ToString)
        End Sub
    
        Private Sub sp_PinChanged(sender As Object, _
                                  e As SerialPinChangedEventArgs) Handles sp.PinChanged
            Debug.WriteLine(e.EventType.ToString)
        End Sub
    
        Private rcvd As New Threading.AutoResetEvent(False)
        Private rcvdThrd As Threading.Thread
    
        Private Sub Receive()
            Do
                If sp.IsOpen Then 'is port open
                    Dim numb As Integer = sp.BytesToRead 'number of bytes to read
                    If numb > 0 Then
                        Dim temp(numb - 1) As Byte 'create a temporary buffer
                        Try
                            numb = sp.Read(temp, 0, numb) 'read the bytes
                            If numb <> temp.Length Then
                                Array.Resize(temp, numb)
                            End If
                            'add temp buffer to public buffer
                            Threading.Monitor.Enter(bufLock)
                            buf.AddRange(temp)
                            Threading.Monitor.Exit(bufLock)
                            procproto.Set() 'check for possible message, see method Protocol
                        Catch ex As Exception
                            'fix error handler
                        End Try
                    End If
                    If sp.BytesToRead = 0 Then
                        rcvd.WaitOne() 'wait for event handler to fire
                    End If
                End If
            Loop While isRun.WaitOne(0)
        End Sub
    
        Private buf As New List(Of Byte)
        Private bufLock As New Object
    
        Private procproto As New Threading.AutoResetEvent(False)
        Private procprotoThrd As Threading.Thread
    
        Private Class MyProto
            Public Property id As Integer = 0
            Public Property lastOther As String = ""
            Public Property ct As Integer = 1
            Private valid As Boolean = False
    
            Public Sub New(someData As String)
                Dim idx As Integer = someData.IndexOf(" "c)
                If idx > 0 AndAlso Integer.TryParse(someData.Substring(0, idx), Me.id) Then
                    Me.lastOther = someData.Substring(idx + 1).Trim
                    If Me.lastOther.EndsWith("***") Then
                        Me.valid = True
                    End If
                End If
            End Sub
    
            Public Function isValid() As Boolean
                Return Me.valid
            End Function
        End Class
    
        Private Sub Protocol()
            Dim messRcvdCt As Integer = 0
            Dim stpw As Stopwatch = Stopwatch.StartNew
            Dim UIstpw As Stopwatch = Stopwatch.StartNew
            Dim cr As Byte = 10 'carriage retrun
            Dim pbuf() As Byte
            Dim addThese As New List(Of MyProto)
            Dim ShowThese As New SortedDictionary(Of Integer, MyProto)
            Do
                'protocol is:
                'id number 
                'space 
                'string that ends with *** 
                'newline
                '
                Dim crIdx As Integer = buf.IndexOf(cr)
                Do While crIdx > 0 'is there a message
                    'yes
                    Threading.Monitor.Enter(bufLock)
                    pbuf = buf.GetRange(0, crIdx).ToArray
                    buf.RemoveRange(0, crIdx + 1)
                    Threading.Monitor.Exit(bufLock)
                    Dim s As String = sp.Encoding.GetChars(pbuf)
                    Dim messFromDevice As New MyProto(s)
                    If messFromDevice.isValid Then
                        messRcvdCt += 1
                        addThese.Add(messFromDevice)
                    End If
                    crIdx = buf.IndexOf(cr)
                Loop
                If addThese.Count > 0 Then 'new messages to add?
                    'yes
                    For Each mp As MyProto In addThese
                        If ShowThese.ContainsKey(mp.id) Then 'exists?
                            ShowThese(mp.id).ct += 1 'yes
                            ShowThese(mp.id).lastOther = mp.lastOther
                        Else
                            ShowThese.Add(mp.id, mp) 'no
                        End If
                    Next
                    addThese.Clear()
                    Try
                        If UIstpw.ElapsedMilliseconds > 50 Then 'update UI 20 times per second
                            UIstpw.Restart()
                            Me.Invoke(Sub()
                                          TextBox1.Text = String.Format("Msgs {0:n0}  Buf {1:n0}   M/s {2:n0} ", messRcvdCt, pbuf.Length, messRcvdCt / stpw.Elapsed.TotalSeconds)
                                          DataGridView1.DataSource = ShowThese.Values.ToList
                                      End Sub)
                        End If
                    Catch ex As Exception
    
                    End Try
                End If
                'End If
                procproto.WaitOne() 'wait for signal to proccess next potential message
            Loop While isRun.WaitOne(0)
        End Sub
    End Class
    


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.




    • Edited by dbasnett Wednesday, September 27, 2017 4:27 PM
    Wednesday, September 27, 2017 12:41 PM
  • Its not clear to me either db so don't feel left out.  :)

    Its nice to see several approaches and pros and cons givens and druthers etc. plus everyone learns learn a lot.  

    Wednesday, September 27, 2017 3:47 PM
  • Its not clear to me either db so don't feel left out.  :)

    Its nice to see several approaches and pros and cons givens and druthers etc. plus everyone learns learn a lot.  

    Thanks.  The last piece of code I posted seems to be running at the bitrate of the port.  About 350 messages / second with about 30 characters / message.

    I wonder if the listview was double buffered would help

                Dim ctrlType As Type
                Dim pi As Reflection.PropertyInfo
    
                ctrlType = ListView1.[GetType]()
                pi = ctrlType.GetProperty("DoubleBuffered", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic)
                pi.SetValue(ListView1, True, Nothing)

    Here  is the app running.  The capture is only of the app but take my word I am moving the window while the capture is happening.

    AppMovie


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.


    • Edited by dbasnett Wednesday, September 27, 2017 5:27 PM
    Wednesday, September 27, 2017 5:15 PM
  • Its not clear to me either db so don't feel left out.  :)

    Its nice to see several approaches and pros and cons givens and druthers etc. plus everyone learns learn a lot.  

    Thanks.  The last piece of code I posted seems to be running at the bitrate of the port.  About 350 messages / second with about 30 characters / message.

    I wonder if the listview was double buffered would help

                Dim ctrlType As Type
                Dim pi As Reflection.PropertyInfo
    
                ctrlType = ListView1.[GetType]()
                pi = ctrlType.GetProperty("DoubleBuffered", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic)
                pi.SetValue(ListView1, True, Nothing)

    Here  is the app running.  The capture is only of the app but take my word I am moving the window while the capture is happening.

    AppMovie


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.


    Hmmm. Well that is an interesting way to set doublebuffer, I mean new to me I mean.

    I dont think the double buffer of the listview will change this timing. That is just a graphics buffer and makes it stop blinking. I have never noticed it taking any time one way or the other.

    But yes I think updating the listview as a real time display should be eliminated if that is happening (is that a listview in your video?). One can see by  commenting that code when timing with a stopwatch. It actually may not be a big percentage of the total?

    I dont get what the listview is for or if there is more than one and what this means:

    "Create lestiview where user Put all info: id, length of message, period in ms, data."

    However in general it would be best to just draw any high speed real time data on the screen. If drawing is done in the paint event and then executed by using control.invalidate it does not tie up the thread.


    Wednesday, September 27, 2017 8:23 PM
  • My display is a datagridview and somewhere along the line I learned that it had a  DoubleBuffered property.  It makes a huge difference.  Does the OP need to resort to using the paint event...?????  Depends on so many factors that are unknown.

    One of the reasons I advocate for not mixing serial port manipulation with the UI is that the serial port is slow, hence my earlier comment about the .Write in the timer event in the OP's code.


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.

    Wednesday, September 27, 2017 9:29 PM
  • Does the OP need to resort to using the paint event...?????  Depends on so many factors that are unknown.

    dbas,

    Yeah I suppose not. I guess one control is probably not controlling the whole thing.

    But using a control.refresh is going back to the system and awaiting that somehow and it can do something I am not sure exactly. I just time things and if taking out the listview update is a 20 percent or more change in the timing then I would look at it.

    Well I did not know that about the datagrid doublebuffered. I mostly use doublebuffer for drawing on a form. As I understand it is just two memory locations and its switched back and forth by ref more or less so it does not change the timing just the display performance. But DGV may be different for some reason (I would think turning doublebuffer off would make it faster). And listview may be a funny one and maybe it does not do doublebuffer at all?

    But like I say I am mostly lost as far as the details and I dont know that much about it anyway.

    Wednesday, September 27, 2017 9:53 PM
  • Sorry,  did not describe the main thing. My Serial Port settings are:

     Private Sub spOpen()
            Try
                spClose()
                spObj.PortName = "COM4"
                spObj.BaudRate = 230400
                spObj.Parity = IO.Ports.Parity.None
                spObj.DataBits = 8
                spObj.StopBits = IO.Ports.StopBits.One
                spObj.Handshake = IO.Ports.Handshake.None
                spObj.DtrEnable = False 'imp
                spObj.RtsEnable = False 'imp
                spObj.NewLine = vbCr
                spObj.ReadTimeout = 0
                spObj.WriteTimeout = 250
                spObj.ReceivedBytesThreshold = 1
                spObj.Open()
    
            Catch ex As Exception
                'catch 
            End Try
        End Sub

    I'm receving Can Bus packeges, mesage format is:

    ID[4byte] Data Length(DLC)[1Byte] Data[8byte max]. So the microcontroller always send 13byte data. Then in vb.net, app exctract the data according to DLC size, fro exmaple CAN-device sent 123[id] 3 bytes: FF AA CC, and dlc will be 3. SO vb.net will get  00000123030000000000FFAACC, so after that, app exctract our 3 byte data, dlc and id.

      dlc = Mid(uart_in, 10, 1)
     data = uart_in.Substring(26 - (dlc * 2))
     can_id = Mid(uart_in, 6, 3) 

    then we do some string maniplation for better looking, as reverse, find ascii and add space after every byte.

     data = String.Join("", Regex.Matches(data, ".{2}").Cast(Of Match).Reverse().Select(Function(M As Match) M.Value).ToArray())
    hex2ascii(data)
    data = data.InsertEveryNthChar(" ", 2)

    Then update listview with that info. 

    @Acamar,  ""send message continously every 50ms," mean send continuously or send every 50ms - they aren't the same thing?  I still can't see that there is a need for multiple timers - it seems that you want to send 3 messages every 50ms, so one timer would be sufficient. "

    Not exactly. Message's ms can vary from 10ms to 1sec. For exmaple i want to send 2 messages. First one with 10ms second one is 500ms. Sso while second one is waiting, first one will already send 50 messages, right? 

    https://www.youtube.com/watch?v=874_uRhGxWs&feature=youtu.be

    In the video i shown, how timers effect on each other while sending and receving, when im not receving - sending timers do pretty well, and do it fast. After i start sending messages and my app get it, sending slows down, then same for receving. I know im doing something wrong, but only doing send like this came to mind




    • Edited by I.newbie Thursday, September 28, 2017 5:17 AM
    Thursday, September 28, 2017 5:14 AM
  • Message's ms can vary from 10ms to 1sec. For exmaple i want to send 2 messages. First one with 10ms second one is 500ms. Sso while second one is waiting, first one will already send 50 messages, right?

    What do you mean by "After i start sending messages and my app get it, sending slows down, then same for receving."   How are you seeing the slowdown?   Or are you referring to the GUI response, not the actual sending or receiving.

    You can monitor the actual sending and receiving by monitoring the buffer sizes. For instance, if the send buffer is filling up then you are supplying data faster than it is being sent - if the buffer size if falling and occasionally sits at zero, then the data is going out faster than you are supplying it.

    You can't use a timer to send messages at 10ms intervals - it just won't work, and it will bog your program down.  But in any case, all you are doing is putting a message into the send queue - it will only actually go when the serial port gets around to senfing it.    So what you can do is concatenate (say) 50 messages into one string and send it at every 500ms.   But that won't have any effect on when they actually get sent - that's under the control of the serial port.   That's a basic feature of serial communications - it takes time.

    Windows cannot achieve the timing precision you are attempting - it is a feature of the OS and the hardware.   If you want to send 50 message at 10ms intervals, use a 500ms timer and send them all at once in each timer tick.  That way you only need one timer - each time it ticks you send 50 message A and one Message B.  That's the best you are going to be able to do with Windows.   If you prepare the messages carefully (that is, not attempting to parse information out of the lines of a Listview) then the UI will remain fully responsive.

    Thursday, September 28, 2017 5:44 AM
  • Message's ms can vary from 10ms to 1sec. For exmaple i want to send 2 messages. First one with 10ms second one is 500ms. Sso while second one is waiting, first one will already send 50 messages, right?

    What do you mean by "After i start sending messages and my app get it, sending slows down, then same for receving."   How are you seeing the slowdown?   Or are you referring to the GUI response, not the actual sending or receiving.

    You can monitor the actual sending and receiving by monitoring the buffer sizes. For instance, if the send buffer is filling up then you are supplying data faster than it is being sent - if the buffer size if falling and occasionally sits at zero, then the data is going out faster than you are supplying it.

    You can't use a timer to send messages at 10ms intervals - it just won't work, and it will bog your program down.  But in any case, all you are doing is putting a message into the send queue - it will only actually go when the serial port gets around to senfing it.    So what you can do is concatenate (say) 50 messages into one string and send it at every 500ms.   But that won't have any effect on when they actually get sent - that's under the control of the serial port.   That's a basic feature of serial communications - it takes time.

    Windows cannot achieve the timing precision you are attempting - it is a feature of the OS and the hardware.   If you want to send 50 message at 10ms intervals, use a 500ms timer and send them all at once in each timer tick.  That way you only need one timer - each time it ticks you send 50 message A and one Message B.  That's the best you are going to be able to do with Windows.   If you prepare the messages carefully (that is, not attempting to parse information out of the lines of a Listview) then the UI will remain fully responsive.

    I'm looking at count in listview, count means how much messages we sent, all i checking this count with another pc which running not my app, called can-bus analyzer so it can receive my message and send messages to me, and my count in listview indentical to what another app has, what means it sending and im receing with same speed. The same story with send with 3 timers. it get all the messages i send. But when i do everying at the same timer send/receive we slows down, and i can see it on can analyzer messages ms slowed down too. 

    What about 1 timer, and all messages at one. It wont work, becaouse microcontroller should extract data with MID statements, and data from vb.net will be always diffrent length in that case. 


    • Edited by I.newbie Thursday, September 28, 2017 6:23 AM
    Thursday, September 28, 2017 6:23 AM
  • What about 1 timer, and all messages at one. It wont work, becaouse microcontroller should extract data with MID statements, and data from vb.net will be always diffrent length in that case. 

    You are confusing speed with timing.

    The messages must be being sent and received at the same speed - the serial connection guarantees that.   Also, you have shown that messages are not being missed - that's good.   But none of that has anything to do with the timing of the messages.   All you really know is that you are loading the messages into the transmit buffer, that they are being sent, and that the other device is receiving them.  But the point is that that process will happen whether you send one message every 10ms or 50 messages every 500ms.    Remembering, of course, that trying to do one message every 10ms will severely interfere with the rest of your processing, including the GUI interactions, causing the lag you are seeing.

    Your last comment seems to indicate a severe misunderstanding of the process.   There is no difference between loading the messages into the serial port device as one large array of bytes covering 50 messages, and loading 50 separate arrays. The data is a stream of bytes communicated to the receiving device.  That device has to work out when each message begins and ends.  That decision is based entirely on the content of the message, and there is nothing you can do at your end to control that.  It is exactly the same task you faced when you were writing your receiving code, except that the roles are reversed.  The MC only knows that a stream of data is being received at its serial port. Therefore it needs to examine that string to examine each byte, build up sequences of bytes, look for a start of message indicator, look for an end of message indicator, and extract the contents between. Exactly the same as you are doing for your receiving.   It doesn't know, and doesn't care, whether that data stream was loaded into your serial port as 50 short arrays of data, or one long array of data. All that matters is that each message in the data stream is formatted correctly so that it can find the start and the end.  Stringing them together to send looks exactly the same to the receiving device as if they had been sent individually.  The difference is that you don't need to be interrupting your application every 10ms - a much longer timer interval is possible.   And that also provides you with the option of just using one timer, and sending the number of messages required according to the message type.

    Thursday, September 28, 2017 7:44 AM
  • Okay... now im totally confused.

     For count = 1 To GetValueFromlv2Row.Length Step 2  'For count = 249 To Text4.Text * 2 Step 8 page 32
                bytestosend(0) = CLng("&H" & Mid(GetValueFromlv2Row, count, 2))
                spObj.Write(bytestosend, 0, bytestosend.Length)
            Next
            spObj.Write(Microsoft.VisualBasic.ControlChars.Cr)
    As you can see, currently im using CR as an indeficator for MC where message ends, 

    By your words, if i want to send 3 messages: 1 message with 500ms delay, 2 of them wih 10 ms, my array should look like 1 meessage & CR & 1 meessage & CR, and total number of messages will be 1001, it will send after 500ms, as array to MC, and MC will be able to handle all data in it?

    Thursday, September 28, 2017 8:07 AM
  • As you can see, currently im using CR as an indeficator for MC where message ends, 

    By your words, if i want to send 3 messages: 1 message with 500ms delay, 2 of them wih 10 ms, my array should look like 1 meessage & CR & 1 meessage & CR, and total number of messages will be 1001, it will send after 500ms, as array to MC, and MC will be able to handle all data in it?

    Do you mean that you have three message types (let's call them A, B and C), and that A and B will be sent at the rate of 100 per second, and C will be sent at the rate of 2 per second (you are still talking in terms of 'delay', but I think you really mean 'rate').

    In that case you would pick a suitable time interval that won't cause a lag in the GUI - lets say 500ms.

    Before you start you will create a message stream like ABABABABABABABABABABABABABABABABABABABABABABABABABCABABABABABABABABABABABABABABABABABABABABABABABABAB.

    Then set the timer interval to 500ms, and at each timer tick, send that data stream.

    If you consider that you are 'adding' a CR to 'separate' the messages then you are looking at it the wrong way.  If the CR is required to mark the end of the message, then it must be thought of as part of the message.  It isn't 'added' like a filler would be, or to make the message stream readable - it is a critical part of the definition of what constitutes a 'message'.

    So the only change you need to make to that code is change the existing spObj.Write to instead append to the buffer, and insert a spObj.Write of the buffer into the timer tick event. 

    Note that 10ms and 500ms is a greater difference than I had assumed.   If the numbers really are like that, then you might need a shorter timer tick (eg, 250ms) in which case you would need to keep tabs on which tick needs the C message included in the data stream (each alternate tick in this example). Some testing might be needed to find the best arrangement.

    Of course, all this change is pointless if you continue to create the messages from the listview instead of from an efficient data source.

    Thursday, September 28, 2017 10:26 AM
  • Newbie,

    Keep something in mind, there is only one cpu. Maybe your system has multiple cpus but, others correct me, you should look at it as though you have one thread running at a time and one cpu.

    So you have to fill the bucket in your app from Reading the serail buffer, then empty the bucket (parse data) in our app. Then send any data. Then update the gui in our app. Then repeat. All we do with the serial port is read and write and we do it in sequence. One then the other. One runs and completes, then do the other , then repeat.

    I dont think you can fill and empty the bucket at the same time in the app but remember there are two buckets. One is the serial port buffer and one is your application memory. But all we have control over is the appliction bucket, and when we read and write the serial data to the serial bucket.

    So the serial port is filling its buffer while we process the data, that is two threads but all we control is our applicastion. When we are done processing, if there is time we update the gui. When that is done we read the next bucket of data from serial buffer. Repeat. At anytime we are only doing one thing in our application and are only in control of one thread. As long as the loop is a long enough time interval and our appliction and bucket is set up right it should work?

    At least that's how I see it this morning. You guys and gals correct me.

    Thursday, September 28, 2017 1:20 PM
  • Okay... now im totally confused.

     For count = 1 To GetValueFromlv2Row.Length Step 2  'For count = 249 To Text4.Text * 2 Step 8 page 32
                bytestosend(0) = CLng("&H" & Mid(GetValueFromlv2Row, count, 2))
                spObj.Write(bytestosend, 0, bytestosend.Length)
            Next
            spObj.Write(Microsoft.VisualBasic.ControlChars.Cr)
    As you can see, currently im using CR as an indeficator for MC where message ends, 

    By your words, if i want to send 3 messages: 1 message with 500ms delay, 2 of them wih 10 ms, my array should look like 1 meessage & CR & 1 meessage & CR, and total number of messages will be 1001, it will send after 500ms, as array to MC, and MC will be able to handle all data in it?

    This looks like you are sending one or two bytes at a time???  Without seeing the datatypes for the variables it is hard to know.  A better approach would be to create an entire message and do one send, especially if this is running on the UI (Form timers run on the UI).

    One other thing, the device expects a certain format when you are sending.  Is it the same as the input format?  Does it expect ControlChars.Cr?  What is the purpose of the send(s).?


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.




    • Edited by dbasnett Thursday, September 28, 2017 9:16 PM
    Thursday, September 28, 2017 2:07 PM
  • Windows cannot achieve the timing precision you are attempting - it is a feature of the OS and the hardware.  

    Unless Windows is an embedded (real-time) version such as is in RTOS: Embedded Real Time Operating Systems. See Why is Windows not considered suitable for real time systems/high performance servers? for a little about the absence of the capability in most Windows versions. In a non-embedded version of Windows if Windows gets busy then it has the option to delay the timer event and that could throw off the timing.

    By the definition of a real-time operating system the OS offers the feature that ensures that timing events are processed at the times they are supposed to. They are used when delays can be deadly, such as nuclear power plants, driverless cars and spacecraft.



    Sam Hobbs
    SimpleSamples.Info

    Thursday, September 28, 2017 6:02 PM
  • @dbasnett

    Yes, im sending by 1 byte, because i want to make sure that MC will recognize the end of the message with CR. So it should read by 1 byte, right? 

    @tommytworain , @Acamar, Thanks for explanation, i got you point very clear, but im lack of code experinece, honestly i dont know hot to implement your thoughts with code.

    Friday, September 29, 2017 9:32 AM
  • Yes, im sending by 1 byte, because i want to make sure that MC will recognize the end of the message with CR. So it should read by 1 byte, right?

    No.  You cannot control how the serial port delivers its data.   Sending one byte at a time makes absolutely no difference to how to the receiving device sees the data stream.  All it knows is that a sequence of bytes is appearing at the serial ort, and that the stream has to be broken down into messages using the start-of-message and end-of-message indicators.  It's the same process you went through writing your data receiving routines.

    The only effect of sending one byte at a time (or one message at a time) is the increased load on your CPU of executing more instructions than is required to get the data into the serial port.

    Friday, September 29, 2017 10:40 AM
  • @dbasnett

    Yes, im sending by 1 byte, because i want to make sure that MC will recognize the end of the message with CR. So it should read by 1 byte, right? 

    @tommytworain , @Acamar, Thanks for explanation, i got you point very clear, but im lack of code experinece, honestly i dont know hot to implement your thoughts with code.

    newbie,

    You should make a simple example with fake data just to get the idea down. Maybe just an array of points that you rill at random in a sub routine called ReadData that is just a dummy serial port that returns random data you make in code.

    It seems to me the code would look like this:

         sub timer tick event

              ReadData (an array or list)

              ParseData (an array or list)

              SendData(second list)

              DrawData(whatever) in the paint event using control.invalidate

         end sub

    If readdata takes up to 10 ms, parsedata takes 20, send and draw 10, you need a timer interval like 10 + 20 + 10 x some factor like 2 = 80 ms. But 500ms might be good too as Acamar says. You just need to play with it to see what range your serial data requires.

    Really not that complicated I think you are making it harder than it is? You do one thing, when its done do the next, in series. Repeat. Just one timer. Four routines in serial.

    Of course there will be more before you are done but for just a simple example seems this is it.

    :)

    PS Its seems to me, without ever doing it, that your needs are very similar to the first example link I gave which just runs on a timer, captures the screen in an array of data for however many frames, when done capturing the data the link example saves the data to disc and then draws the screen. Then exits the timer routine back to the system. Next timer tick repeat.

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/7d3860d9-5dc8-4b86-a258-85cbfc567ed0/saving-1-image-every-16-millisecond-in-vb?forum=vbgeneral

    Sometimes we just have to work through examples as see the thing operating one line of code at a time. Each example we see more and see things we need for our project.

    PS the link example actually uses threading for the timer but you would just use the windows forms timer. So not exactly the same but same principle. Do one thing, then the next, exit timer sub, repeat next timer tick.

    Friday, September 29, 2017 12:58 PM
  • @dbasnett

    Yes, im sending by 1 byte, because i want to make sure that MC will recognize the end of the message with CR. So it should read by 1 byte, right? 

    @tommytworain , @Acamar, Thanks for explanation, i got you point very clear, but im lack of code experinece, honestly i dont know hot to implement your thoughts with code.

    @OP  -  I created a project out of the code from above.  A couple of changes in the Shown event and you might see a different way to approach this.  The changes are the settings for the Serial Port and commenting the line that starts the loopback simulator I used to test. 

    The binaries were deleted before the .Zip file was created. Good luck.

    The link for the project is:

    CAN Serial Test

    What it looks like:

    Screen Capture v2


    Note that the message per second shown in the capture are for the receive only.  The program was sending all of those packets to itself using a loop back plug attached to my serial port.


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.





    • Edited by dbasnett Saturday, September 30, 2017 2:27 PM
    Friday, September 29, 2017 4:54 PM
  • db,

    I don't seem to be able to see the Screen Capture video? Is the link working?

    Friday, September 29, 2017 7:27 PM
  • db,

    I don't seem to be able to see the Screen Capture video? Is the link working?

    It should've worked, but I did it again and named it v2 in the post.  It is a one drive read only link. 

    Did you get an error? Were you able to get the project?


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.

    Saturday, September 30, 2017 2:29 PM
  • db,

    I don't seem to be able to see the Screen Capture video? Is the link working?

    It should've worked, but I did it again and named it v2 in the post.  It is a one drive read only link. 

    Did you get an error? Were you able to get the project?


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.


    Oh. The video wont run in ie 11 latest. It just says there was a problem loading the video where the video image should be in the player.

    Joy it works in FireFox.

    I see. Seems to run fairly fast.

    I have not tried the project code as I dont have a serial port and I dont really understand it anyway. However I will run it if you want me too. :)

    Saturday, September 30, 2017 2:53 PM
  • db,

    I don't seem to be able to see the Screen Capture video? Is the link working?

    It should've worked, but I did it again and named it v2 in the post.  It is a one drive read only link. 

    Did you get an error? Were you able to get the project?


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.


    Oh. The video wont run in ie 11 latest. It just says there was a problem loading the video where the video image should be in the player.

    Joy it works in FireFox.

    I see. Seems to run fairly fast.

    I have not tried the project code as I dont have a serial port and I dont really understand it anyway. However I will run it if you want me too. :)


    IE!  Figures.  I was curious to see if the project would download to determine if it was the video or both.  It is up to you.

    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.

    Sunday, October 1, 2017 4:23 PM

  • IE!  Figures.  I was curious to see if the project would download to determine if it was the video or both.  It is up to you.

    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.

    dbas,

    Ok then. Downloaded (ie11) and tested vs2015. Runs to the stop in form shown. I don't have com1 (I think) seems thats what should happen.

    So it works!

    Sunday, October 1, 2017 4:47 PM
  • db,

    I don't seem to be able to see the Screen Capture video? Is the link working?

    It should've worked, but I did it again and named it v2 in the post.  It is a one drive read only link. 

    Did you get an error? Were you able to get the project?


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    


    Oh. The video wont run in ie 11 latest. It just says there was a problem loading the video where the video image should be in the player.

    Joy it works in FireFox.

    I see. Seems to run fairly fast.

    I have not tried the project code as I dont have a serial port and I dont really understand it anyway. However I will run it if you want me too. :)


    IE!  Figures.  I was curious to see if the project would download to determine if it was the video or both.  It is up to you.

    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    

    Thanks for your share @dbasnett. Seems like i cant check out the project you shared - https://youtu.be/6x4OddGS9qY ( on :09sec i send single message from can device). I changed serialport settings that my port requaried(com port name and baudrate), and commented loopback simulator:

     rcvdThrd.Start()
            Try
                'Modify settings as needed <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                sp.PortName = "COM4"
                sp.BaudRate = 230400
                sp.DataBits = 8
                sp.Parity = Parity.None
                sp.StopBits = StopBits.One
                sp.WriteTimeout = 100
                sp.Encoding = System.Text.Encoding.GetEncoding(28591) 'default is 7 bit ascii, this is 8 bit
                sp.Open()
    
                ' SimulateDevice() '<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Comment this line if connected to device <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
            Catch ex As Exception
                Stop
            End Try

    . App stops with "stop" when im trying to send single message once(not emulator, using real device) message is 0000012808AAAAAAAAAAAAAAAA - first 4 bytes are id, then 1 byte - dlc, and 8 bytes are data, so it's equal with protocol you used in project(commented section):

         'protocol is:
                'ID 4 bytes
                'DLC Data Length 1 Byte - 1 to 8
                'Data 8 bytes max 
    Maybe im missing something crucial...


    • Edited by I.newbie Monday, October 2, 2017 7:53 AM
    Monday, October 2, 2017 7:50 AM
  • Thanks for your share @dbasnett. Seems like i cant check out the project you shared - https://youtu.be/6x4OddGS9qY ( on :09sec i send single message from can device). I changed serialport settings that my port requaried(com port name and baudrate), and commented loopback simulator:
     rcvdThrd.Start()
            Try
                'Modify settings as needed <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                sp.PortName = "COM4"
                sp.BaudRate = 230400
                sp.DataBits = 8
                sp.Parity = Parity.None
                sp.StopBits = StopBits.One
                sp.WriteTimeout = 100
                sp.Encoding = System.Text.Encoding.GetEncoding(28591) 'default is 7 bit ascii, this is 8 bit
                sp.Open()
    
                ' SimulateDevice() '<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Comment this line if connected to device <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
            Catch ex As Exception
                Stop
            End Try

    . App stops with "stop" when im trying to send single message once(not emulator, using real device) message is 0000012808AAAAAAAAAAAAAAAA - first 4 bytes are id, then 1 byte - dlc, and 8 bytes are data, so it's equal with protocol you used in project(commented section):

         'protocol is:
                'ID 4 bytes
                'DLC Data Length 1 Byte - 1 to 8
                'Data 8 bytes max 
    Maybe im missing something crucial...


    Where did it stop?

    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.

    Monday, October 2, 2017 1:03 PM

  • Where did it stop?

    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.

    dbas,

    Must mean on the STOP statement in the try/catch?

    Newbie should maybe remove the try/catch and report the line and err msg?


    PS Newbie should be sure that Visual Studio is set to break on the proper type of error, CLR? in menu Debug - Exceptions dialog.
    Monday, October 2, 2017 1:24 PM

  • Where did it stop?

    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.

    dbas,

    Must mean on the STOP statement in the try/catch?

    Newbie should maybe remove the try/catch and report the line and err msg?


    PS Newbie should be sure that Visual Studio is set to break on the proper type of error, CLR? in menu Debug - Exceptions dialog.

    If it stops there then the exception(ex) information should have the cause of the error.

    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.

    Monday, October 2, 2017 1:59 PM
  • It's here:

         If someData.Count >= 6 Then 'min message size is 6 bytes
                    If Threading.Monitor.TryEnter(someDataLock) Then
                        If someData(4) >= 1 Then
                            If someData(4) <= 8 Then
                                If someData.Count >= (5 + someData(4)) Then
                                    Me._incomplete = False
                                    'get id 
                                    Dim tid As List(Of Byte) = someData.GetRange(0, 4)
                                    tid.Reverse() 'may not be required, but based on sample it likely is required
                                    Me.ID = BitConverter.ToInt32(tid.ToArray, 0)
                                    'get DLC
                                    Me.LenData = someData(4)
                                    Me.RcvdBytes = Me.LenData
                                    Me.DataBytes = someData.GetRange(5, Me.LenData)
                                    'convert data to hex
                                    Dim sb As New System.Text.StringBuilder
                                    For Each b As Byte In Me.DataBytes
                                        sb.AppendFormat("{0,-3:X2}", b)
                                    Next
                                    Me.HexData = sb.ToString
                                    Me.valid = True
                                    someData.RemoveRange(0, 5 + Me.LenData)
                                Else
                                    Incomplete()
                                    Debug.WriteLine(someData.Count)
                                End If
                            Else
                                Stop
                                Me._incomplete = False 'error length > 8
                            End If
                        Else
                            Stop
                            Me._incomplete = False 'error length < 1
                        End If
                        If Not Me.valid AndAlso Not Me._incomplete Then
                            Stop
                            someData.RemoveAt(0) 'error
                        End If
                        Threading.Monitor.Exit(someDataLock)
                    Else
                        Debug.WriteLine(someData.Count)
                    End If
                End If
            End Sub
    so if i remove first stop, then second stop drops, after comment second - third drops. When i commented all three - nothing happens. By the way, im really want to figure out this code and make it work. Because your video demostrates that all smooth in UI, Appreciate your kindness

    Wednesday, October 4, 2017 6:46 AM
  • If you are hitting the stops in the code you posted then you'll need to debug it.  Maybe the protocol description you gave is incorrect or I implemented incorrectly. 

                'protocol is:
                'ID 4 bytes
                'DLC Data Length 1 Byte - 1 to 8
                'Data 8 bytes max
                '

    Looking at someData when it enters the code above should give you an idea. 

    One other thought; is the device only sending the messages you described?  If not the code will have to be modified to accommodate those messages.


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.


    • Edited by dbasnett Wednesday, October 4, 2017 11:34 AM
    Wednesday, October 4, 2017 11:02 AM
  • If you are hitting the stops in the code you posted then you'll need to debug it.  Maybe the protocol description you gave is incorrect or I implemented incorrectly. 

                'protocol is:
                'ID 4 bytes
                'DLC Data Length 1 Byte - 1 to 8
                'Data 8 bytes max
                '

    Looking at someData when it enters the code above should give you an idea. 

    One other thought; is the device only sending the messages you described?  If not the code will have to be modified to accommodate those messages.


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    


    this is what i send from MC every time:

    Print Hex(canid_idx) ; Hex(breceived_idx) ; Hex(recdobule_idx);

    (This is basic code syntax);

    First exception is - 

    If someData(4) <= 8 Then

    as i understand this one is data length. 

    our protocol  = 4byte, 1byte, 8byte. SO it should be correct

    Thursday, October 5, 2017 7:24 AM
  • Did you look at what was received?  Does DLC actually have the correct length of the data?  From what you said it should always say 8, does it?

    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.

    Thursday, October 5, 2017 11:52 AM
  • No, i send data as hex, 4 bytes(dword) as can id, 1 byte as DLC(byte), dlc can be 1 to 8, but its always 1 byte. and 8 bytes(double) data. thats a protocol. 13bytes.
    Friday, October 6, 2017 6:25 AM
  • No, i send data as hex, 4 bytes(dword) as can id, 1 byte as DLC(byte), dlc can be 1 to 8, but its always 1 byte. and 8 bytes(double) data. thats a protocol. 13bytes.

    In one of your posts you said that DLC was length, and even agreed with the comments in the code.  It has no meaning basically.

    Try replacing the private class CanDeviceProto with this

        Private Class CanDeviceProto
            Public Property ID As Integer = 0
            Public Property LenData As Integer = 0
            Public Property HexData As String = ""
            Private DataBytes As List(Of Byte)
            Public Property RcvCT As Integer = 1
            Public Property RcvdBytes As Long = 0L
            Private valid As Boolean = False
            Private _incomplete As Boolean = True
    
            Public Sub New(ByRef someData As List(Of Byte), ByRef someDataLock As Object)
                'protocol is:
                'ID 4 bytes
                'DLC Data Length 1 Byte - 1 to 8 - ignore
                'Data 8 bytes max 
                '
                If someData.Count >= 13 Then 'min message size is 13 bytes
                    If Threading.Monitor.TryEnter(someDataLock) Then
                        Me._incomplete = False
                        'get id 
                        Dim tid As List(Of Byte) = someData.GetRange(0, 4)
                        tid.Reverse() 'may not be required, but based on sample it likely is required
                        Me.ID = BitConverter.ToInt32(tid.ToArray, 0)
                        'get DLC
                        Me.LenData = someData(4)
                        Me.RcvdBytes = 13
                        Me.DataBytes = someData.GetRange(5, 8)
                        'convert data to hex
                        Dim sb As New System.Text.StringBuilder
                        For Each b As Byte In Me.DataBytes
                            sb.AppendFormat("{0,-3:X}", b)
                        Next
                        Me.HexData = sb.ToString
                        Me.valid = True
                        someData.RemoveRange(0, 13)
                        Threading.Monitor.Exit(someDataLock)
                    Else
                        ' Debug.WriteLine(someData.Count)
                    End If
                End If
            End Sub
    
            Public Function Incomplete() As Boolean
                Return Me._incomplete
            End Function
    
            Public Function isValid() As Boolean
                Return Me.valid
            End Function
        End Class
    


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.

    Friday, October 6, 2017 11:50 AM
  • Did that help?

    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.

    Tuesday, October 10, 2017 11:28 AM
  • Sorry for not replying too long, didnt have access to PC. Will test it tomorrow...
    Wednesday, October 11, 2017 7:38 AM
  • Did that help?

    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    

    Hello db, i tested your code, we have some progress, i can see data in the form, so i receiving, the problem that the data is totally mess.  this is what i receive: https://imgur.com/BzwE3y1 

    its wrong. id should be 3 chars, data 8bytes, and leanth 1 byte

    Thursday, October 12, 2017 7:36 AM
  • Did that help?


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    

    Hello db, i tested your code, we have some progress, i can see data in the form, so i receiving, the problem that the data is totally mess.  this is what i receive: https://imgur.com/BzwE3y1 

    its wrong. id should be 3 chars, data 8bytes, and leanth 1 byte

    Previously you said

    "our protocol  = 4byte, 1byte, 8byte. SO it should be correct"  That is 13 bytes, and now it looks like you are saying 12.

    At this point I am lost myself, and not being able to see the data makes it difficult.  Maybe you can step through the code and see what it is doing.

    Apparently we are 12 hours apart so this is a message a day :(


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.


    • Edited by dbasnett Thursday, October 12, 2017 10:57 AM
    Thursday, October 12, 2017 10:56 AM
  • Did that help?


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    

    Hello db, i tested your code, we have some progress, i can see data in the form, so i receiving, the problem that the data is totally mess.  this is what i receive: https://imgur.com/BzwE3y1 

    its wrong. id should be 3 chars, data 8bytes, and leanth 1 byte

    Previously you said

    "our protocol  = 4byte, 1byte, 8byte. SO it should be correct"  That is 13 bytes, and now it looks like you are saying 12.

    At this point I am lost myself, and not being able to see the data makes it difficult.  Maybe you can step through the code and see what it is doing.

    Apparently we are 12 hours apart so this is a message a day :(


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    


    Yes, right. 13bytes. it think i miss spelled at this point.

    i did a simple test, sending 1 message over and over again through do-loop with 100ms. The message was: 000128080000000000555555.  what i got: https://imgur.com/a/1n1uP. As you can see  data and id is wrong. Im pretty sure the error somewhere in the vb.net app, but i cant find it. Code seems too strong for me

    Monday, October 16, 2017 6:52 AM
  • i did a simple test, sending 1 message over and over again through do-loop with 100ms. The message was: 000128080000000000555555.  what i got: https://imgur.com/a/1n1uP. As you can see  data and id is wrong. Im pretty sure the error somewhere in the vb.net app, but i cant find it. Code seems too strong for me

    You should consider that your original code was working, but needed to be modified so that you could use a longer timer tick interval while still maintaining the same data transmission rate.  That was an easy change that only needed the construction of a multi-message buffer to be usable with that original code.  That code was also easily upgradeable to a more sophisticated processing mode that did not poll.  It seems to me that you would be better off making that change to your original code rather than attempting to debug new code that requires you to master a very different processing structure.

    Monday, October 16, 2017 7:22 AM
  • fixed data, data displeying ocrrect now
    Monday, October 16, 2017 7:37 AM
  • i did a simple test, sending 1 message over and over again through do-loop with 100ms. The message was: 000128080000000000555555.  what i got: https://imgur.com/a/1n1uP. As you can see  data and id is wrong. Im pretty sure the error somewhere in the vb.net app, but i cant find it. Code seems too strong for me

    You should consider that your original code was working, but needed to be modified so that you could use a longer timer tick interval while still maintaining the same data transmission rate.  That was an easy change that only needed the construction of a multi-message buffer to be usable with that original code.  That code was also easily upgradeable to a more sophisticated processing mode that did not poll.  It seems to me that you would be better off making that change to your original code rather than attempting to debug new code that requires you to master a very different processing structure.

    Hello Acamar. I Agreed. But the huge problem with my current code - not updating data in the UI. As i noticed eariler, my count is not smooth, its updating value in the UI thread, with 10 -20 jump. And as i said - im ok with that. But, after i tried real CAN device which sending around 20 diffrent IDs continiously, and data changes every time  for each of that ID, and my listview just doesnt show all of the data we get in listview's data column - its unacceptable
    , becaouse its neccesary to make UI thread updating data properly for human's eye, but my programm cant catch up all of the updates, some of them updating - another not, then that was not updating - updates, and that was updating - stops, then all by new. I was checking all messages i got in "ParseData" sub with Richtextbox4
             If Button4.Text = "STOP" Then
                            If TextBox1.Text = "" Then
    
                                RichTextBox4.AppendText(DateTime.Now.ToString("ss,fffff") & vbTab & vbTab & can_id & vbTab & dlc & vbTab & spacefortrace & vbCrLf)
                            End If
                            If TextBox1.Text <> "" And TextBox1.Text.Contains(can_id) Then
                                RichTextBox4.AppendText(DateTime.Now.ToString("ss,fffff") & vbTab & vbTab & can_id & vbTab & dlc & vbTab & spacefortrace & vbCrLf)
                            End If
    
                        End If
    It shows me that i get all messages i need, but UI doesnt update all of them in listview, seems like its just jumps over of that message instead of updating them in the UI. Whats more funny, the low i make timer's interval, the faster it updates UI, with 250ms - it's not updating all of the data, 50ms makes it 3 times faster consider to what i see in listview update. Also as i said earlier i need to be able to send messages with timer's interval, and all of my tests came to only decition - using new timer for each continous message, and from my tests it works  until i not run receving data, so it means that  my parsedata with timer1 effects on my UI. Can you help me Acamar, with the problem of speeding up my UI, because i tried a lot of things. I tried to make all parsing in DataRecevined event - it didnt work, because from my observe - event doesnt allow parsing to be finished, it just fire every time we have data in the serial buffer. i even tried to make do loop with thread.sleep, and changing priorty with the thread 
    Dim System.Threading.Thread yourthread As New System.Threading.Thread(AddressOf yourfunction())
    yourthread.Priority = System.Threading.Priority.Highest
    yourthread.Start();
    It makes all things even worse. Thats why i was trying to figure out dbasnett's code, because thats all i have 
     

    • Edited by I.newbie Tuesday, October 17, 2017 8:38 AM
    Tuesday, October 17, 2017 8:35 AM
  • I tried to make all parsing in DataRecevined event - it didnt work, because from my observe - event doesnt allow parsing to be finished, it just fire every time we have data in the serial buffer.

    Your original code needed more than one change.  The first one was to increase the timer interval to something that actually allowed some processing (in particular, the UI updating) to occur between timer ticks.  Then you needed to improve the code so that the amount of work to be done in each timer tick was reduced to a minimum, to ensure that the updating followed the data received as closely as possible.   When you get to the stage that the UI is updating properly, but is delayed or only happens in spurts, then you know that each improvement in the code will smooth things out.   Deleting the DoEvents was a start.   Next would be the code that stops and starts the timers - that's completely unnecessary if the tick interval is sufficient.  For the sending, you then needed to send multiple messages at longer timer ticks, so that the code required at each timer tick is minimized.  For receiving you need to change from polling the I/O buffer to using the DataReceived event and polling an internal, managed buffer.  If you go back to the original discussion the idea of trying to parse in the DataReceived event was dismissed very early on - it's not even worth attempting.   The only thing that should happen in the data received event is to add the data received to the buffer. Polling the internal buffer will then work, but for efficiency it can be changed to using a delegated function, but that's an easy change that can be done at any time.   If you are still seeing the time available in the data received event as insufficient to do the parsing, then that indicates that you have not considered the point that was made at the time - parsing must be done in the UI thread, and you need an indicator of the buffer size so that you can see whether or not the parsing is keeping up with the data flow.    Note that if the parsing code is too complex to be completed in time (that is, the buffer is added to faster than it is deleted from) then you know that the code you have to work on is the parsing and UI updating, and there are lots of options there.  No rearrangement of the procedure is going to mask inefficient UI updating. And I have no idea what you were trying to achieve with that threading code, but I can't imagine that it could have improved things.  Threading is designed to improve responsiveness (eg, responding to data received at the serial port) - it doesn't give you any more processing power, which is what you need if the UI updating is inefficient.
    • Proposed as answer by tommytwotrain Tuesday, October 17, 2017 12:25 PM
    Tuesday, October 17, 2017 9:12 AM
  • I tried to make all parsing in DataRecevined event - it didnt work, because from my observe - event doesnt allow parsing to be finished, it just fire every time we have data in the serial buffer.

    Your original code needed more than one change.  The first one was to increase the timer interval to something that actually allowed some processing (in particular, the UI updating) to occur between timer ticks.  Then you needed to improve the code so that the amount of work to be done in each timer tick was reduced to a minimum, to ensure that the updating followed the data received as closely as possible.   When you get to the stage that the UI is updating properly, but is delayed or only happens in spurts, then you know that each improvement in the code will smooth things out.   Deleting the DoEvents was a start.   Next would be the code that stops and starts the timers - that's completely unnecessary if the tick interval is sufficient.  For the sending, you then needed to send multiple messages at longer timer ticks, so that the code required at each timer tick is minimized.  For receiving you need to change from polling the I/O buffer to using the DataReceived event and polling an internal, managed buffer.  If you go back to the original discussion the idea of trying to parse in the DataReceived event was dismissed very early on - it's not even worth attempting.   The only thing that should happen in the data received event is to add the data received to the buffer. Polling the internal buffer will then work, but for efficiency it can be changed to using a delegated function, but that's an easy change that can be done at any time.   If you are still seeing the time available in the data received event as insufficient to do the parsing, then that indicates that you have not considered the point that was made at the time - parsing must be done in the UI thread, and you need an indicator of the buffer size so that you can see whether or not the parsing is keeping up with the data flow.    Note that if the parsing code is too complex to be completed in time (that is, the buffer is added to faster than it is deleted from) then you know that the code you have to work on is the parsing and UI updating, and there are lots of options there.  No rearrangement of the procedure is going to mask inefficient UI updating. And I have no idea what you were trying to achieve with that threading code, but I can't imagine that it could have improved things.  Threading is designed to improve responsiveness (eg, responding to data received at the serial port) - it doesn't give you any more processing power, which is what you need if the UI updating is inefficient.
    making a code efficient is hard, because i need all functions and controls at the moment. And making things like MID() faster is impossible because no faster alternative for that.
    Thursday, October 19, 2017 10:28 AM
  • making a code efficient is hard, because i need all functions and controls at the moment. And making things like MID() faster is impossible because no faster alternative for that.
    Replacing the Mid() function with something more efficient is easy, but is not a high priority.  Changes like getting the parsing out of the data received event into the UI thread is much more important as a first step.
    Thursday, October 19, 2017 11:32 AM
  • making a code efficient is hard, because i need all functions and controls at the moment. And making things like MID() faster is impossible because no faster alternative for that.

    Serial port questions tend to be difficult because of the protocol and how people communicate with the port, especially data reception.  I tried to show an abbreviated version of what I typically do.  I understand that it seems difficult.  This thread prompted me to write an explanation of the code and post it to the TechNet wiki as AN answer for all serial port questions.  It is up to you to read it or not.  Acamar has some good advice.  Hope the two of you figure it out.

    Serial Port


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.

    Thursday, October 19, 2017 3:22 PM