Total newb trying to read incoming serial port data in hex

  • (2 Pages)
  • +
  • 1
  • 2

24 Replies - 3903 Views - Last Post: 26 February 2013 - 10:47 AM Rate Topic: -----

#16 dbasnett  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 109
  • View blog
  • Posts: 603
  • Joined: 01-October 08

Re: Total newb trying to read incoming serial port data in hex

Posted 21 February 2013 - 11:20 AM

View Postmike944, on 21 February 2013 - 11:23 AM, said:

Because lar3ry said the event handler executes when there is data waiting in the port buffer, I was just assuming that there is at least one byte waiting, so I am reading and processing each byte as soon as it's ready. This dispenses with the complexity of a checking loop to see if the right number of bytes are available. (but, it adds a loop to assemble the frame)

If i understand your code correctly, you're waiting until there is a full frame waiting, right?


When the event handler fires there will be at least .ReceivedBytesThreshold bytes available to be read. There may be more, but there won't be less. My code reads as many bytes as are available at the time the event fires. It then adds those bytes to the end of the list. That is all that it does. If the device is sending 26 bytes the event handler might fire several times. The event ONLY fires when new data has arrived. This means that if you receive 13 bytes, then another 13 bytes, the event handler will only fire twice.

You could try my code and put breakpoints in the event handler to see how it works. The same goes for the timer. The timer has a Stop already.

Threading.Monitor keeps separate pieces of code from manipulating objects from multiple threads. The DataReceived handler runs on a different thread the UI thread, so it is entirely possible that you have two pieces of code executing at the same time(if you have multiple cores), or nearly the same time. The timer runs on the UI thread. The UI thread is the only one that can manipulate controls on the form.

Here is a link that might ;)/>/> help http://msdn.microsof...v=vs.90%29.aspx

Here is the code as one piece. I make no promises that it works because I don't have a device that runs your protocol.

    Dim dataB As New List(Of Byte)
    Dim dataLock As New Object

    Private Sub SerialPort1_DataReceived(sender As Object, _
                                         e As IO.Ports.SerialDataReceivedEventArgs) _
                                     Handles SerialPort1.DataReceived
        Dim numBytes As Integer = SerialPort1.BytesToRead 'get # of bytes available
        Dim buf(numBytes - 1) As Byte 'allocate a buffer
        Dim br As Integer = SerialPort1.Read(buf, 0, numBytes) 'read the bytes
        If br <> numBytes Then
            Array.Resize(buf, br)
        End If
        Threading.Monitor.Enter(dataLock)
        dataB.AddRange(buf)
        Debug.WriteLine(String.Format("Event:  BytesRead - {0},  Bytes buffered - {1}", br, dataB.Count))
        Threading.Monitor.Exit(dataLock)
    End Sub

    Dim WithEvents timer1 As New Windows.Forms.Timer

    Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
        timer1.Interval = 100 '10 times per second
        timer1.Start()
    End Sub


    Private Sub timer1_Tick(sender As Object, e As EventArgs) Handles timer1.Tick
        If dataB.Count >= 26 Then
            'might be a frame
            Threading.Monitor.Enter(dataLock)

            Do While dataB.Count > 1
                If dataB(0) = 255 AndAlso dataB(1) = 255 Then
                    If dataB.Count >= 26 Then
                        Dim b() As Byte = dataB.ToArray 'for debugging only
                        Debug.WriteLine("FFFF found at 0")
                        'process frame


                        'remove frame just processed
                        dataB.RemoveRange(0, 26)
                    Else
                        Exit Do
                    End If
                Else
                    dataB.RemoveAt(0)
                End If
            Loop

            Threading.Monitor.Exit(dataLock)
        End If
    End Sub


This post has been edited by dbasnett: 22 February 2013 - 06:21 AM

Was This Post Helpful? 0
  • +
  • -

#17 lar3ry  Icon User is offline

  • Coding Geezer
  • member icon

Reputation: 310
  • View blog
  • Posts: 1,290
  • Joined: 12-September 12

Re: Total newb trying to read incoming serial port data in hex

Posted 21 February 2013 - 01:17 PM

View Postmike944, on 21 February 2013 - 11:23 AM, said:

dbasnett -
Because lar3ry said the event handler executes when there is data waiting in the port buffer, I was just assuming that there is at least one byte waiting, so I am reading and processing each byte as soon as it's ready. This dispenses with the complexity of a checking loop to see if the right number of bytes are available. (but, it adds a loop to assemble the frame)

You should be assembling the data as it comes in. Don't read just one byte each tiem through the DataReeived event. The loop is hardly complex. get SerialPort1.BytesToRead, then use that as a counter to grab all the available data. Collect it up, then pass it to a function. Let the function worry about where the frames start and what to do with them. As well, let the function tack any data received onto its own variable or into its own array, so that there is no need for the serial port to worry about the data it's already got.

Quote

I figured my method would also be better for error-checking. if i loose one or more bytes, and i see a start code before i was expecting one, i need to discard the partial frame and start over. i'm not sure how i do that with your method of waiting for 26 bytes. If i loose a byte mid-frame, then the tail byte could actually be the first start code for the next frame.
In addition, for the initialization, i shouldn't start capturing a full frame until i know i've recieved the 2 start bytes.

Again, let the function you pass the data to, decide what to do. Just send it everything that comes in. Let it look for frame start, count the bytes, resync if it needs to, and display the results.

Quote

Can i read the bytes, yet leave them in the buffer?

No. Once they are read, they are no longer in the serial port buffer. But again, don't bother doing anything with the data in the DataReceived event. Just pass it on.

Quote

BTW, they coming in at 40 frames/second. 26 bytes per frame, so 1040 bytes/sec. is that considered "REAL fast"?

No, that's not real fast. It's not even somewhat fast
Was This Post Helpful? 1
  • +
  • -

#18 dbasnett  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 109
  • View blog
  • Posts: 603
  • Joined: 01-October 08

Re: Total newb trying to read incoming serial port data in hex

Posted 22 February 2013 - 06:29 AM

Looking over what I posted last yesterday I realized that the timer1.Tick handler could be simpler. I edited the post with the new code, but here it is.

    Private Sub timer1_Tick(sender As Object, e As EventArgs) Handles timer1.Tick
        If dataB.Count >= 26 Then
            'might be a frame
            Threading.Monitor.Enter(dataLock)

            Do While dataB.Count > 1
                If dataB(0) = 255 AndAlso dataB(1) = 255 Then
                    If dataB.Count >= 26 Then
                        Dim b() As Byte = dataB.ToArray 'for debugging only
                        Debug.WriteLine("FFFF found at 0")
                        'process frame


                        'remove frame just processed
                        dataB.RemoveRange(0, 26)
                    Else
                        Exit Do
                    End If
                Else
                    dataB.RemoveAt(0)
                End If
            Loop

            Threading.Monitor.Exit(dataLock)
        End If
    End Sub


Was This Post Helpful? 1
  • +
  • -

#19 mike944  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 20
  • Joined: 17-February 13

Re: Total newb trying to read incoming serial port data in hex

Posted 22 February 2013 - 08:28 AM

Thanks for all the help guys!

I wasn't able to work on this last night, but i'll try this weekend.

Thanks for the simplistic code. I've been learning a LOT. i think i actually follow most of what's going on in your last post.

You're using the timer event to check the buffer on an interval, and waiting for at least 26 bytes. you're then checking to see if the first 2 bytes are both 255. if so, you're storing the frame in B(), if not, you're removing the first byte, and checking again for 255,255 right?

There seem to be SO many possible commands, you've helped me out by showing me a bunch of useful ones for this application. xx.ReadByte, xx.BytesToRead, Debug.xx, xx.RemoveAt, xx.RemoveRange, AndAlso, etc...


How many bytes can the serial port buffer hold before it starts to overflow? I think i'm going to have to run the timer event faster than 10/second. Data is coming in at 40 frames/sec. I think i need to read it at least that fast, otherwise it's going to back up with unread data. (i expect to read and display data continuoiusly for 8-10 hours at a time)

I'll mess with it this weekend, and let you know how i make out.

Thanks again for the help!
Was This Post Helpful? 0
  • +
  • -

#20 dbasnett  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 109
  • View blog
  • Posts: 603
  • Joined: 01-October 08

Re: Total newb trying to read incoming serial port data in hex

Posted 22 February 2013 - 08:39 AM

" if so, you're storing the frame in B(), if not, you're removing the first byte, and checking again for 255,255 right?"

Actually yes and no. You can remove Dim b() As Byte = dataB.ToArray 'for debugging only. Your frame will be the first 26 bytes of dataB. The code does check for 255,255 as the first two bytes of the buffer.

The default buffer size for the SerailPort is 4096 bytes I think.

Whether you change the timer or not depends on how much processing you do.
Was This Post Helpful? 0
  • +
  • -

#21 mike944  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 20
  • Joined: 17-February 13

Re: Total newb trying to read incoming serial port data in hex

Posted 22 February 2013 - 09:39 AM

View Postdbasnett, on 22 February 2013 - 08:39 AM, said:

Actually yes and no. You can remove Dim b() As Byte = dataB.ToArray 'for debugging only. Your frame will be the first 26 bytes of dataB. The code does check for 255,255 as the first two bytes of the buffer.


Ah, i see. so Datab() would be the variable holding the incoming data that i would be able to access in the other subs, not b(), right?

View Postdbasnett, on 22 February 2013 - 08:39 AM, said:

Actually yes and no. You can remove Dim b() As Byte = dataB.ToArray 'for debugging only. Your frame will be the first 26 bytes of dataB. The code does check for 255,255 as the first two bytes of the buffer.


Ah, i see. so Datab() would be the variable holding the incoming data that i would be able to access in the other subs, not b(), right?
Was This Post Helpful? 0
  • +
  • -

#22 mike944  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 20
  • Joined: 17-February 13

Re: Total newb trying to read incoming serial port data in hex

Posted 22 February 2013 - 09:48 AM

I guess i don't know how to edit existing posts....to remove the double-post. Whatever.

Since that sub doesn't look for start codes (except in the debug section), passing the data in blocks of 26 bytes is now arbitrary, right? they won't necessarily be a full frame. it could be the tail of one frame, and the start of another. Statistically, it will be, right? I'll have to add at least 2 frames together in the receiving sub to guarantee i have at least one full frame after i find the 255,255
Was This Post Helpful? 0
  • +
  • -

#23 dbasnett  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 109
  • View blog
  • Posts: 603
  • Joined: 01-October 08

Re: Total newb trying to read incoming serial port data in hex

Posted 22 February 2013 - 10:13 AM

View Postmike944, on 22 February 2013 - 10:48 AM, said:

I guess i don't know how to edit existing posts....to remove the double-post. Whatever.

Since that sub doesn't look for start codes (except in the debug section), passing the data in blocks of 26 bytes is now arbitrary, right? they won't necessarily be a full frame. it could be the tail of one frame, and the start of another. Statistically, it will be, right? I'll have to add at least 2 frames together in the receiving sub to guarantee i have at least one full frame after i find the 255,255


I don't understand. The code in the timer isn't debug. Here it is again without your code to process the frame. The timer could be called several times before a full frame is found, or it might find several frames when it is called. My suggestion is try it and see, then go from there.

    Private Sub timer1_Tick(sender As Object, e As EventArgs) Handles timer1.Tick
        Const frmStrt As Byte = &HFF ' 33 'frame start - so I can test
        'might be a frame
        Threading.Monitor.Enter(dataLock)

        Do While dataB.Count > 1 'might process more than one frame
            If dataB(0) = frmStrt AndAlso dataB(1) = frmStrt Then
                If dataB.Count >= 26 Then
                    'to get here you need two start characters (FFFF)
                    'and 24 other bytes.
                    'dataB(0)dataB(1)dataB(2)...dataB(24)dataB(25)

                    'put your code that processes the frame
                    Stop 'here



                    'then remove frame
                    dataB.RemoveRange(0, 26)
                Else
                    Exit Do
                End If
            Else
                dataB.RemoveAt(0)
            End If
        Loop

        Threading.Monitor.Exit(dataLock)

    End Sub


This post has been edited by dbasnett: 22 February 2013 - 10:17 AM

Was This Post Helpful? 0
  • +
  • -

#24 mike944  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 20
  • Joined: 17-February 13

Re: Total newb trying to read incoming serial port data in hex

Posted 25 February 2013 - 09:01 PM

Got it working. Just wanted to say thanks, and let you know what's been going on.

I mostly used the suggestions here, with some mods.

I've learned a lot. I think i mostly understand what's going on in that code. Thanks.

Now that i have the frames coming in correctly, i was able to get down to the heart of the code, which is processing the data into something useful. I'm starting to break the frames up into values, and working to display them. I've also added a lost-frame checking routine, which looks for increases in clock ticks/frame (i'm ticking at 100x a second)

Now i'm starting to work on displaying it correctly. I'm sure i'll end up with more questions, but i'll start a new thread.

Thanks again!
Mike
Was This Post Helpful? 0
  • +
  • -

#25 dbasnett  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 109
  • View blog
  • Posts: 603
  • Joined: 01-October 08

Re: Total newb trying to read incoming serial port data in hex

Posted 26 February 2013 - 10:47 AM

Glad I could help.
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2