Total newb trying to read incoming serial port data in hex

  • (2 Pages)
  • +
  • 1
  • 2

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

#1 mike944  Icon User is offline

  • New D.I.C Head

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

Total newb trying to read incoming serial port data in hex

Posted 17 February 2013 - 04:36 PM

ok, i'm a total newbe at VB (or any object-oriented languages for that matter)

I'm trying to write a simple app for myself only, that can read continuous data coming into a serial port from a microcontroller. I eventually want to display it in a bunch of tachometer-like dials, but i'm a long ways from that point.

At this point, my trouble is i'm trying to learn how to read the incoming data, to make sure it's coming in successfully, and it's not.

I've doing a lot of surfing, and learning. I found plenty of stuff on how to read data from serial ports, including this tutorial that i followed: http://tiktakx.wordp...th-vb-net-2010/ That seems to work, but all i get in my output box is garbage: ??%?.???????? etc... I assume that's because i can't interpret hex that way.

I have been searching for how to read this data in hex, but all of the solutions i find online are too high-level for me to understand. I see people posting one-line code fixes, but i'm REALLY new, and i need more explanation on how to adjust them to match what i'm doing, and where to put them.

Here's the guts of my program, just like the tutorial shows:

Private Sub SerialPort1_DataReceived(sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
        ReceivedText(SerialPort1.ReadExisting())    'Automatically called every time a data is received at the serialPort
    End Sub

Private Sub ReceivedText(ByVal [text] As String)
        'compares the ID of the creating Thread to the ID of the calling Thread
        If Me.rtbReceived.InvokeRequired Then
            Dim x As New SetTextCallback(AddressOf ReceivedText)
            Me.Invoke(x, New Object() {(text)})
        Else
            Me.rtbReceived.Text &= [text]
        End If
    End Sub





From reading online about hex data, I think i need to edit the first sub code to be
ReceivedText = Hex(SerialPort1.ReadExisting()


but i get an error: "Argument not specified for parameter 'text' of 'Private Sub ReceivedText(text As String)". I'm REALLY new, and don't understand what that means, so I click the autocorrect "Generate property stub...." which generates:
 Private Property ReceivedText As String 
in the public class area at the top of my code.

That now gives me a different error on the second sub of "ReceivedText is already declared...." I do understand that i can't declare a variable twice, but my sub has the same name as my variable, and i can't figure out how to make "Private Property ReceivedText As String" and "Private Sub ReceivedText(ByVal [text] As String)" to do both things.

Sorry if this is something obvious i'm doing wrong, but i'm really new, and can't figure this out. I'm trying to learn here, so i'd appreciate low-level explanations of what i'm doing wrong, and/or how to fix it.


Thanks,
Mike

Is This A Good Question/Topic? 0
  • +

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

#2 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 17 February 2013 - 06:55 PM

You could start by changing the name of either your function or your variable. There is no need to have them noth the same name.
Was This Post Helpful? 0
  • +
  • -

#3 mike944  Icon User is offline

  • New D.I.C Head

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

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

Posted 18 February 2013 - 12:25 PM

I already tried that. I forget whether i got an error, or it executed wrong, but it didn't work. (i'm not near my computer with visual studio on it right now)

The complete code is longer than that, but all 3 instances of the name "ReceivedText" appear in the snippet below.

I believe I tried renaming line 2 and 8 (above) to something else. Are you saying i should rename the subroutine in line 5? I don't understand how this sub gets called, or what the "(ByVal [text] As String)" in the sub name actually does.


My post was already long enough, i didn't want to detail everything i tried. probably because what i tried didn't necessarily make sense.
Was This Post Helpful? 0
  • +
  • -

#4 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 18 February 2013 - 01:57 PM

OK, I think I see what's happening here. I gather you got this code from somewhere and have been trying to modify it. In the process, you ended up with a subroutine and variable of the same name, which of course id definitely not good.

I also see that there are some funky things happening in that code, like setting up a callback. Depending on exactly what you are trying to read from the serial port, and what you are doing with it, there's a simpler way.

Here's a simple bit of code for your serial port DataReceived handler. I have included a global declaration for a string variable to hold your received data.

Private rcvData As String

    Private Sub SerialPort1_DataReceived(sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
        rcvData &= SerialPort1.ReadExisting
        'call a function or Sub here, eg
        'DoStuff()
    End Sub



Any data arriving at the serial port will cause this handler to execute. When that happens, the global variable rcvData will contain one or more characters. Since you don't know how many characters will be there, or whether the full data packet (whatever that consists of) is present, it will be up to you to handle the data. It's easy enough to find the length, and to test for particular characters in the data.

In order to actually handle the data, some other subroutine or function will need to be activated. You can do this by calling a subroutine or function from inside the above handler, as shown.

Now as to your 'garbage' characters coming in, that may or may not be a result of non-printable characters coming in. The serial port parameters have to be matched to the data coming in. If you have the Now as to your 'garbage' characters coming in, that may or may not be a result of non-printable characters coming in. The serial port parameters have to be matched to the data coming in. Number of stop bits, Parity, and baud rate all have to match. If they don't, 'garbage' characters will result.

Work on what I've mentioned here, and let me know how things work out. Especially, let me know what sort of data should be coming in from the device. We can work on the Hex when the data starts coming in.
Was This Post Helpful? 0
  • +
  • -

#5 mike944  Icon User is offline

  • New D.I.C Head

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

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

Posted 19 February 2013 - 04:22 PM

Ok, thanks for the info. Simpler is better here, because i don't know what i'm doing!

That ReceivedText sub, with the callback seems to be required to "Make Thread-Safe Calls to Windows Forms Controls". http://msdn.microsof...#code-snippet-3

When replaced the questionable code in my first post with yours, i had to add back a check of the invokerequired property (per the MS documentation above) to eliminate a cross-thread call error.

Again, keep in mind, i'm quoting this from documentation, and only somewhat sure of what it really means.



Over that time, i've learned that i don't want to use the hex( statement to convert, i want val( to convert from hex to . Except when i try that i get some run-time error about unable to convert. Perhaps the string is too long? Should i be using a different function to convert?


I know the data is in hex, and my port parameters are correct. I found program that views incoming hex data and displays it, and i can see the data, and it's good.

The data coming in is a frame of 26 bytes, the first 2 frames are FF FF





I'm going to chew on this for a few days. My computer with VS and my source of hex serial data are not in the same location as i am right now, so i'm going to have to wait to try a few things.

I'll post back with any more troubles

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

#6 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 19 February 2013 - 05:49 PM

View Postmike944, on 19 February 2013 - 05:22 PM, said:

That ReceivedText sub, with the callback seems to be required to "Make Thread-Safe Calls to Windows Forms Controls". http://msdn.microsof...#code-snippet-3

When replaced the questionable code in my first post with yours, i had to add back a check of the invokerequired property (per the MS documentation above) to eliminate a cross-thread call error.

Again, keep in mind, i'm quoting this from documentation, and only somewhat sure of what it really means.


Hmmm... were you actually getting a cross-thread call error? If so, were you specifically starting a separate thread? I don't use threading much at all. I am currently working on a telemarketing-buster program that recognizes spam calls by number, and if it detects one that's on the list, I use the modem to pick up and drop the phone line, I don't use any separate thread in there, or at least I don't specifically make one. So if you're creating a separate thread, I won't be of much use in helping.

Quote

Over that time, i've learned that i don't want to use the hex( statement to convert, i want val( to convert from hex to . Except when i try that i get some run-time error about unable to convert. Perhaps the string is too long? Should i be using a different function to convert?

I know the data is in hex, and my port parameters are correct. I found program that views incoming hex data and displays it, and i can see the data, and it's good.

The data coming in is a frame of 26 bytes, the first 2 frames are FF FF

You do realize that all bytes are Hex, right? That is, they are in binary, 8 bits of ones and zeros, but they can ALL be represented as Hex. It comes in handy, sometimes, to observe what the bytes are, and Hex is probably the best way to see them clearly.

Your two first bytes, for example, are all ones, or 255 if looked at as unsigned bytes. Using Val() on those will not yield a value. Val works on string representations of numbers and (sometimes) decimal points, so the valid bytes for using a Val() function to yield a number are 30-39 and 2E Hex.

The most useful reason to convert to Hex is to make the data human-readable, so you can see what the data actually is.

So, are the other 24 bytes strings (ASCII values of printable and control characters? Or are they actual data values? If the latter, you'll need to know how to interpret them; as individual bytes, two-byte integers, four-byte integers, etc. (and are they high-endian or low-endian?)

Quote

I'll post back with any more troubles

Please do!
Was This Post Helpful? 0
  • +
  • -

#7 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 19 February 2013 - 06:34 PM

When reading from the SerialPort in character mode, the encoding of the port is applied. To see raw bytes use .Read

This code should give you an idea.

    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
        SerialPort1.Read(buf, 0, numBytes) 'read the bytes
        Debug.WriteLine("")
        For Each b As Byte In buf
            Debug.WriteLine(Convert.ToString(b, 16))
        Next
    End Sub


Was This Post Helpful? 0
  • +
  • -

#8 mike944  Icon User is offline

  • New D.I.C Head

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

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

Posted 19 February 2013 - 07:26 PM

View Postlar3ry, on 19 February 2013 - 05:49 PM, said:

Hmmm... were you actually getting a cross-thread call error? If so, were you specifically starting a separate thread? I don't use threading much at all. I am currently working on a telemarketing-buster program that recognizes spam calls by number, and if it detects one that's on the list, I use the modem to pick up and drop the phone line, I don't use any separate thread in there, or at least I don't specifically make one. So if you're creating a separate thread, I won't be of much use in helping.


Yes, i was getting a compile error. Apparently i was starting a separate thread, but i don't really know what that means, so i certainly wasn't doing it intentionally.


Quote

You do realize that all bytes are Hex, right? That is, they are in binary, 8 bits of ones and zeros, but they can ALL be represented as Hex. It comes in handy, sometimes, to observe what the bytes are, and Hex is probably the best way to see them clearly.


I guess i never really thought of it that way. The documentation said the device sends in hex bytes, which i know can represent 0-255, and most of the byte strings are designed to represent an analog value from 0-255. a few of the strings i need to separate into bits, and read the bits separately. those represent individual high/low values.

Quote

Your two first bytes, for example, are all ones, or 255 if looked at as unsigned bytes. Using Val() on those will not yield a value. Val works on string representations of numbers and (sometimes) decimal points, so the valid bytes for using a Val() function to yield a number are 30-39 and 2E Hex.


ok, so that explains my trouble.

Quote

The most useful reason to convert to Hex is to make the data human-readable, so you can see what the data actually is.


I never thought that making it human readable and using the data would be 2 different things. I was looking to make them human readable, because i wanted to know that my program was working.

Quote

So, are the other 24 bytes strings (ASCII values of printable and control characters? Or are they actual data values? If the latter, you'll need to know how to interpret them; as individual bytes, two-byte integers, four-byte integers, etc. (and are they high-endian or low-endian?)


As i said above, each byte is to represent a value from 0-255, and i want to get my program to be able to process those values. Some will be displayed as-is, others will need scale factors applied. I know how to do the math, and i already figured out how to get the display i want working in another program. my problem is receiving the data that i can't figure out.
Was This Post Helpful? 0
  • +
  • -

#9 mike944  Icon User is offline

  • New D.I.C Head

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

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

Posted 19 February 2013 - 07:39 PM

View Postdbasnett, on 19 February 2013 - 06:34 PM, said:

When reading from the SerialPort in character mode, the encoding of the port is applied. To see raw bytes use .Read

This code should give you an idea.

    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
        SerialPort1.Read(buf, 0, numBytes) 'read the bytes
        Debug.WriteLine("")
        For Each b As Byte In buf
            Debug.WriteLine(Convert.ToString(b, 16))
        Next
    End Sub



Ah, so you mean SerialPort1.ReadExisting reads in "character mode" and SerialPort1.Read reads in raw bytes?

Ok, so if i want to read in 26-byte frames, should i have some kind of loop to keep checking number of bytes available until it hits 26, and then read 26? or should i keep reading in single bytes until i get 2 sequential FF's, and then read 24 more bytes?

I do need to process them in frames, because each byte in the frame means something different, and i actually need to test one of the bytes in the frame to see which frame it is. (there are 3 different frames)

ok, so these are some things to try. Unfortunately it might be a few days before i can get back to my code, and my device.

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

#10 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 19 February 2013 - 10:43 PM

View Postmike944, on 19 February 2013 - 08:39 PM, said:

Ah, so you mean SerialPort1.ReadExisting reads in "character mode" and SerialPort1.Read reads in raw bytes?

.Read reads in bytes. If you assign the return value to a Byte array, you can do Byte-sh things to them. If you assign them to a character array, then you can do Char-ish things to them. .Read is for reading Bytes or chars into arrays of the appropriate type. It lets you specify how many bytes to read.

You can use .ReadByte, which will read a single byte, returning it as a byte, cast to an Int32. This is probably the one you want to use, though it's really up to you. You can even use that Int32 to figure out which bits are 1s and which are 0s.

Quote

Ok, so if i want to read in 26-byte frames, should i have some kind of loop to keep checking number of bytes available until it hits 26, and then read 26? or should i keep reading in single bytes until i get 2 sequential FF's, and then read 24 more bytes?

It's completely up to you. I would suggest reading (or scanning an array or string) until you find a frame, then grab the data in the frame, then process or display it how you wish. You will need to sync up with the frames to start with, if your board supplies data continuously.

Quote

I do need to process them in frames, because each byte in the frame means something different, and i actually need to test one of the bytes in the frame to see which frame it is. (there are 3 different frames)

The right way to do it would be to make a class in which you define your frames, supply methods to process the frames and functions to return whatever values you need, in whatever format is most useful.
Was This Post Helpful? 0
  • +
  • -

#11 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 20 February 2013 - 06:55 AM

View Postmike944, on 19 February 2013 - 08:39 PM, said:

Ah, so you mean SerialPort1.ReadExisting reads in "character mode" and SerialPort1.Read reads in raw bytes?

Ok, so if i want to read in 26-byte frames, should i have some kind of loop to keep checking number of bytes available until it hits 26, and then read 26? or should i keep reading in single bytes until i get 2 sequential FF's, and then read 24 more bytes?

I do need to process them in frames, because each byte in the frame means something different, and i actually need to test one of the bytes in the frame to see which frame it is. (there are 3 different frames)

ok, so these are some things to try. Unfortunately it might be a few days before i can get back to my code, and my device.

Thanks!


I generally keep the event handler to a minimum. In this case I would read the bytes and buffer them in a list. In a timer or separate thread I would scan the list looking for the protocol, and process the data accordingly.

    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)
        Threading.Monitor.Exit(dataLock)
    End Sub


Was This Post Helpful? 0
  • +
  • -

#12 mike944  Icon User is offline

  • New D.I.C Head

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

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

Posted 21 February 2013 - 07:35 AM

Ok, so thanks everybody! I got it working.

i'm using SerialPort1.ReadByte I'm currently reading and processing it as one byte at a time. my code is probably extremely inefficient, but it seems to be working.

I know it's very inefficient, i'm doing all the processing in the serial port DataReceived handler, and just calling a display subroutine to display the 3 frames after i've collected 3 full frames.


I actually got quite far last night. I used the help above, and figured out how to read it. (i'm using ReadByte) I'm converting it into an interger immediately after reading it, and i'm processing it as a number. I'm also successfully searching for, and finding the 2 frame start bytes (two sequential 255 values), and also taking 2 of the bytes, breaking them down into bits, and reading certain bit positions to determine which of the 3 possible frames it is, and storing the frames in three arrays of length 26.

Currently i'm just displaying them on the screen to make sure it's working correctly, and it seems to be. I am also extracting and displaying the framenumber (which is one of the bytes) in a textbox.

once i get all the processing working, i'll certainly want to clean it up, and "keep the event handler to a minimum", but i'm way more concerned with actually getting it working. Right now, i'm doing everything in the eventhandler.


If i did want to process it separately, how does the code below pass the received value back to anything? one of you said that sub is called by data arriving at the port, not by some other portion of the code, right? so there's no calling subroutine to return a value to, right? what code would run after this event handler? how do i ensure that the processing code executes appropriately after the data recieved event? should i call is with a sub from the data recieved event handler routine?
Was This Post Helpful? 0
  • +
  • -

#13 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 - 08:12 AM

So using the other code I posted add this, which is not complete, but has some hints. The timer runs on the UI which is convenient. Also pay attention to the Threading.Monitor statements which are required because there is a possibility of two threads accessing dataB at the same time.

    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)

            Dim idx As Integer = dataB.IndexOf(255)
            If idx < dataB.Count - 1 Then
                If dataB(idx + 1) = 255 Then
                    Stop
                    'idx points at start of frame
                    'other checks needed to see if there are 24 more bytes
                    'if so, process them
                    'then remove them
                    'dataB.RemoveRange(idx, 26)
                End If
            End If

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


This post has been edited by dbasnett: 21 February 2013 - 08:14 AM

Was This Post Helpful? 0
  • +
  • -

#14 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 - 10:03 AM

View Postmike944, on 21 February 2013 - 08:35 AM, said:

If i did want to process it separately, how does the code below pass the received value back to anything? one of you said that sub is called by data arriving at the port, not by some other portion of the code, right? so there's no calling subroutine to return a value to, right? what code would run after this event handler? how do i ensure that the processing code executes appropriately after the data recieved event? should i call is with a sub from the data recieved event handler routine?

I don't know how fast your data is coming in, but if it isn't REAL fast, you might want to gather up a full frame, then call a function that parses and uses the data, then get rid of the frame you just passed, and look for the next one.
Was This Post Helpful? 0
  • +
  • -

#15 mike944  Icon User is offline

  • New D.I.C Head

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

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

Posted 21 February 2013 - 10:23 AM

dbasnett -

So i didn't directly use your post #11 code, because i didn't totally understand how it was working.

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?

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. Can i read the bytes, yet leave them in the buffer?



Here's where my lack of knowledge of modern programing really shows through. What exactly is a "thread" and do they truely run simultaneously, or does one interrupt the execution of the other to run. What does the threading.monitor do? Does it keep the dataB index variable from one thread separate from the index variable in the other thread, and allow them to both access different index positions simultaneously?

There's also lots of other stuff i don't understand, like what the Me. does



BTW, they coming in at 40 frames/second. 26 bytes per frame, so 1040 bytes/sec. is that considered "REAL fast"?
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2