Xtreme Visual Basic Talk

Xtreme Visual Basic Talk (http://www.xtremevbtalk.com/)
-   .NET Communications (http://www.xtremevbtalk.com/-net-communications/)
-   -   Serial port (com port) reading data (http://www.xtremevbtalk.com/-net-communications/326422-serial-port-com-port-reading-data.html)

StealthRT 09-14-2013 12:43 PM

Serial port (com port) reading data
 
I have a valentine 1 radar and also the V1Connect (bluetooth adaptor) for it hooked to my PC via a Virtual Serial Port (COM 16).

I am trying to read the data coming from it but all i am getting is gibberish.

My VB.net code is this:
Code:

    Private pendingMsg As New stringbuilder

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        For Each s In System.IO.Ports.SerialPort.GetPortNames()
            lstPorts.Items.Add(s)
        Next s
    End Sub

    Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
        Dim completedMsg As String
        completedMsg = String.Empty
        pendingMsg.Append(SerialPort1.BytesToRead())

        If pendingMsg.Length >= 24 Then
            completedMsg = pendingMsg.ToString
            Debug.Print(completedMsg)
        End If
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        SerialPort1.BaudRate = 57600
        SerialPort1.DataBits = 8
        SerialPort1.Parity = IO.Ports.Parity.None
        SerialPort1.StopBits = IO.Ports.StopBits.One
        SerialPort1.PortName = "COM16" 'lstPorts.SelectedItem.ToString
        SerialPort1.Open()
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        SerialPort1.Close()
        txtReceived.Text = ""
    End Sub

and the gibberish output is this:
Code:

71919383957767795114129133
71919383957767795114129133152
71919383957767795114129133152167
71919383957767795114129133152167171
71919383957767795114129133152167171190
71919383957767795114129133152167171190191
71919383957767795114129133152167171190191209
71919383957767795114129133152167171190191209228
71919383957767795114129133152167171190191209228229
71919383957767795114129133152167171190191209228229247
71919383957767795114129133152167171190191209228229247266
71919383957767795114129133152167171190191209228229247266280
71919383957767795114129133152167171190191209228229247266280285
71919383957767795114129133152167171190191209228229247266280285304
71919383957767795114129133152167171190191209228229247266280285304311
71919383957767795114129133152167171190191209228229247266280285304311323
71919383957767795114129133152167171190191209228229247266280285304311323342
71919383957767795114129133152167171190191209228229247266280285304311323342343
71919383957767795114129133152167171190191209228229247266280285304311323342343361
71919383957767795114129133152167171190191209228229247266280285304311323342343361380
71919383957767795114129133152167171190191209228229247266280285304311323342343361380382
71919383957767795114129133152167171190191209228229247266280285304311323342343361380382399
71919383957767795114129133152167171190191209228229247266280285304311323342343361380382399418
71919383957767795114129133152167171190191209228229247266280285304311323342343361380382399418419
71919383957767795114129133152167171190191209228229247266280285304311323342343361380382399418419437
71919383957767795114129133152167171190191209228229247266280285304311323342343361380382399418419437456

The datasheets for the V1 are:
http://i.stack.imgur.com/IMIG2.jpg

http://i.stack.imgur.com/UnKUU.jpg

http://i.stack.imgur.com/vJpe6.jpg

http://i.stack.imgur.com/bJFar.jpg

http://i.stack.imgur.com/cTnhn.jpg

The full PDF for the ESP can be found http://www.valentine1.com/eula/eula.asp?d

passel 09-14-2013 07:56 PM

Don't have time to test what String Builder does when appending bytes from a serial port, but I assume it isn't that useful.
The documentation indicates you will be getting messages made up of various number of bytes depending on the message id, so as a minimum you should be reading the serial data into a byte array, and then look for the framing bytes and when you have a complete message, framed by the SOF (AA hex, which would be 170 decimal) and EOF (AB hex, 171 decimal) and then byte offset 3 within the mesage would identify the packet ID, and 4 the length (so you would use the byte values directly as numbers, not as a character). You would then decode the rest of the bytes in the packet in accordance to the specification.

StealthRT 09-14-2013 08:23 PM

This is my current code:
Code:

Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
        Dim b As Integer

        SerialPort1.ReadTimeout = 50

        Try
            Do While SerialPort1.BytesToRead > 0
                b = SerialPort1.ReadByte
                Me.BeginInvoke(New mydel(AddressOf txt_out), b)
            Loop
        Catch ex As Exception

        End Try
    End Sub

    Private Sub txt_out(ByVal i As Integer)
        txtReceived.AppendText("&H" & i.ToString("X2") & " ")
    End Sub

I am now getting this:
Code:

&H7F &H0F
&HAA &HD8 &HEA &H31 &H09 &H00 &H00 &H00 &H00 &H00 &H0A &H00 &H00 &HB0 &HAB
&H1A &H7F &H7F &H0F
&HAA &HD8 &HEA &H31 &H09 &H00 &H00 &H00 &H00 &H00 &H0A &H00 &H00 &HB0 &HAB
&H1A &H7F &H7F &H0F
&HAA &HD8 &HEA &H31 &H09 &H00 &H00 &H00 &H00 &H00 &H0A &H00 &H00 &HB0 &HAB
&H1A &H7F &H7F &H0F
&HAA &HD8 &HEA &H31 &H09 &H00 &H00 &H00 &H00 &H00 &H0A &H00 &H00 &HB0 &HAB
&H1A &H7F &H7F &H0F
&HAA &HD8 &HEA &H31 &H09 &H00 &H00 &H00 &H00 &H00 &H0A &H00 &H00 &HB0 &HAB
&H1A &H7F &H7F &H0F
 
&HAA &HD8 &HEA &H31 &H09 &H73 &H73 &H00 &H00 &H00 &H0A &H00 &H00 &H96 &HAB
&HE6 &H7F &H7F &H0F
&HAA &HD8 &HEA &H31 &H09 &H73 &H73 &H00 &H00 &H00 &H0A &H00 &H00 &H96 &HAB
&HE6 &H7F &H7F &H0F
&HAA &HD8 &HEA &H31 &H09 &H73 &H73 &H00 &H00 &H00 &H0A &H00 &H00 &H96 &HAB
&HE6 &H7F &H7F &H0F
&HAA &HD8 &HEA &H31 &H09 &H73 &H73 &H00 &H00 &H00 &H0A &H00 &H00 &H96 &HAB
&HE6 &H7F &H7F &H0F
&HAA &HD8 &HEA &H31 &H09 &H73 &H73 &H00 &H00 &H00 &H0A &H00 &H00 &H96 &HAB
&HE6 &H7F &H7F &H0F
&HAA &HD8 &HEA &H31 &H09 &H73 &H73 &H00 &H00 &H00 &H0A &H00 &H00 &H96 &HAB
&HE6 &H7F &H7F &H0F
&HAA &HD8 &HEA &H31 &H09 &H73 &H73 &H00 &H00 &H00 &H0A &H00 &H00 &H96 &HAB
&HE6 &H7F &H7F &H0F
&HAA &HD8

I see the &HAA(start) and the &HD8(end) but how do i separate each of those start and ends without keep adding to it?

AtmaWeapon 09-15-2013 09:31 AM

Imagine your StringBuilder is a bucket. And the data coming from the serial port is yummy fruit juice, a different flavor every time. You hold the bucket under the spigot, then look to see what you got. Apple juice! Then you put the bucket (still half-full of apple juice) back under the spigot. OK, now you have a mix of apple and cranberry juice; that was harder to identify but still possible. 10 samples later, you can't tell what the heck's going on.

This is what you're doing when constantly appending data to the StringBuilder. The simple (and wrong) answer to, "How do I identify the separate start and end sections" would be, "Write code that loops over each byte and finds each start/end marker." Why is that wrong? It's like saying to our metaphorical spigot bucket guy, "You fool! Your fruit juice bucket needs these hundreds of little dividers so you can separate all the juices!"

Empty the bucket. StringBuilder has a Clear() method or something similar. Take one sample, do something with it, then clear your buffer. If you approach the spigot with an empty bucket, it's easy to see what is in it.

(Incidentally, neither approach is really wrong. Sometimes you want to take one sample at a time. In that case it's best to use a new bucket each time. Other times you want to take many samples and process them later. That's *why* there's a start/end section in the protocol: so you can take one stream of bytes and figure out how to divide it up. But in your example program, there's no reason to keep the old data around.)

passel 09-15-2013 04:34 PM

1 Attachment(s)
Since you're not dealing with character data, I don't think that discussing the StringBuilder class is really useful here. I admit I haven't used it a lot, but I suspect it is not real useful for dealing with collecting and decoding the numeric bytes and discrete bits necessary when dealing with a hardware interface protocol.

Since the hardware will most likely be already transmitting when you start your application, you may start receiving data in the middle of the stream (as your dump indicates), and data can be corrupted, so you pretty much have to continually verify that you are sync'd to the packets and have verified they are complete and correct before processing them. If a check fails, you ignore that packet and move on to the next.
This is especially important since your SOF value AA, could appear in the data payload as well as your EOF value of AB, so you can't just assume that because you found an AA and an AB, that they do frame a valid packet.

The task of dealing with a serial stream of interface packets like this I usually divided into at least two parts (but more likely into several parts to handle decoding the packets at various levels of detail, i.e. a task to receive and buffer the incoming stream, a task to identify, verify and perhaps extract a complete packet, a task to parse the given packet, and a task to process the parse data and act on it).
But, at the highest level, the two parts would be:
1. Buffer the incoming data, identify and verify a proper packet structure, and
2. call a parser to process the packet.

Once you get in sync with the packet traffic, there is the chance that there may be sufficient time between messages that you can safely clear a buffer and start receiving a new packet at the beginning of a new packet, but usually this is not something to count on when dealing with a serial interface. My preference is to use a ring buffer so that the receiver is adding bytes to the buffer, and the packet processor is removing bytes from the buffer in a simple to implement cycle, rather than using multiple buffers to copy and shuffle bytes around.
Since your dump is showing an extra four (unidentified at this point) bytes between packets that you'll probably ignore at this point, is all the more reason to find and verify the packets that you are interested in and ignore the rest.

Given what you have, you should do the following to identify and verify you have a properly formatted packet.
1. Find the AA byte. (Note what offset in your buffer you find the AA)
2. Verify you have at least 5 bytes after the AA (the shortest packet you can have would be 6 bytes, including the SOF and EOF. If you don't have at least five bytes after the AA, you can't possibly have a full packet so it is a waste to verify anything now, leave a "pointer", i.e. index pointing to your AA, and when you receive more data, start again from 1 (your code will find the AA at the first byte pointed to)
3. You have enough bytes, so read the fifth byte (fourth after the AA) to get the length of the packet. Add that number to your pointer and if you have enough bytes in your buffer, read the byte from that location. If you don't have enough bytes in the buffer, just leave and try again after you've received more data.
4. The byte read in step 3 (AA + len) should be your EOF byte AB. If it is not, then this is not a proper frame. Increment the pointer pointing to the AA byte to advance to the next byte and start at step 1, searching for the next AA byte in your buffer.
5. Once you've found the AA byte, and the AB byte at the proper offset specified in the packet, then if this packet has a checksum byte (determined from the packet ID), you can loop through bytes generate the checksum and compare it to the one from the packet. If they agree you can process the packet, otherwise increment you pointer and start searching again.

Now since whether there is a checksum or not depends on the packet ID, you may not want to have that information at this level of the process, i.e. you want the packet finder/verifier to know about SOF, EOF, and where to find the length of the packet, but not have to know the details of which packet formats have checksums, and which don't.
You may just want to send the "packet" as verified by SOF,EOF and length to a routine that handles processing the packet id, and selecting the decoding processor. That task can do the checksum calculation and choose to process the packet (checksum matches), or drop it.

I edited your post above to separate the stream into sections, mostly so we don't have a tremendously long line to make the web page harder to deal with, but also it kind of represents what you will need to do in code, and that is to identify the packets in the stream.
Since you printed the values in hex, we can fairly easily hand decode a packet to see what it is. The process used to hand decode the packet should give you insight into what you need your code to do to parse the packet.
Code:

&H7F &H0F

&HAA                SOF (Start of Frame)

&HD8                Destination ID:                8        (General Broadcast)
&HEA                Originator ID:                10      (Valentine One with checksums)
&H31            Packet Identifier:        0x31    (InfDisplayData) "all the information needed to rebuild thr front panel display. plus status bytes"
&H09            Payload Length:                9 bytes
&H00            Bogey Counter Image 1 :        bits to drive 7 segement display
&H00            Bogey Counter Image 2 :        bits to drive 7 segement display
&H00                Signal Strength Bar  : bits drive 8 block bar graph
&H00                Band and Arrow Image 1: bits represent discretes to drive various indicators
&H00                Band and Arrow Image 2: same bit definition as image1
&H0A                Aux0                      : 0X0A decoded bits: Display On, TS Holdoff
&H00            Aux1                      : Reserved for futurer use
&H00            Aux2                      : Reserved for futurer use
&HB0                Checksum

&HAB                EOF
 
&H1A &H7F &H7F &H0F

&HAA &HD8 &HEA &H31 &H09 &H00 &H00 &H00 &H00 &H00 &H0A &H00 &H00 &HB0 &HAB
&H1A &H7F &H7F &H0F
'.....
'                        Here you see the two 7 segment display drivers
'                        now have the value 0x73 in them. If 7 segment drive bits are fairly standard
'                        then I would interpret the display to be like "PP", see attached png file.
&HAA &HD8 &HEA &H31 &H09 &H73 &H73 &H00 &H00 &H00 &H0A &H00 &H00 &H96 &HAB
The bits from 0 to 7 represent segments A - G and dp
'0X73 = 01110011 binary
'      dGFEDCBA segments
'      p


StealthRT 09-15-2013 05:45 PM

I've tried doing this:
Code:

Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
        Dim b As Integer

        SerialPort1.ReadTimeout = 50

        Try
            Do While SerialPort1.BytesToRead > 0
                b = SerialPort1.ReadByte

                If b = 127 Then Debug.Print(b.ToString("X2"))
                Me.BeginInvoke(New mydel(AddressOf txt_out), b)
            Loop
        Catch ex As Exception

        End Try
    End Sub

    Private Sub txt_out(ByVal i As Integer)
        If "&H" & i.ToString("X2") = "&HAA" And buildPacket = False Then
            buildPacket = True
            blah = "&H" & i.ToString("X2")
        ElseIf "&H" & i.ToString("X2") = "&HAB" Then
            buildPacket = False
            blah += blah & " &H" & i.ToString("X2")
            txtReceived.AppendText(blah)
            blah = ""
        ElseIf buildPacket Then
            blah += blah & " &H" & i.ToString("X2")
        End If

        'txtReceived.AppendText("&H" & i.ToString("X2") & " ")
    End Sub

But that doesnt seem to break up the data in the packets..

I ran another scan and this is what its outputting with the original code:
Code:

&H7F &H0F

&HAA
&HD8
&HEA
&H31
&H09
&H77
&H77
&H00
&H00
&H00
&H0C
&H00
&H00
&HA0
&HAB
&HFA

&H7F &H7F &H0F
&HAA
&HD8
&HEA
&H31
&H09
&H77
&H77
&H00
&H00
&H00
&H0C
&H00
&H00
&HA0
&HAB
&HFA


passel 09-15-2013 10:10 PM

Well, one thing I said incorrectly is that you would read the Message ID to determine if the message had a checksum, but in looking at the document again (and it was implied in the comment in my hand decoded packet), is that the Originating ID of 10 (0xE0 + 10 = 0xEA) indicates that the packets will use a checksum byte. If the Originating ID was 9 (0xE0 + 9 = E9) then the packets would not have a checksum byte.

I wouldn't do nearly as much string conversions as you do. Generally the only time to convert numbers to strings is when you have to display them, not to compare them, or collect them or operate on them.

Why not create an array of bytes to act as a temporary buffer. You can use the Read method of the Serial port to read data into that array at a given offset, so you can real all the available bytes into the array in one swoop, and accumulate the bytes by keeping track of the next position in the array to be written to, and reading future bytes into that array at an offset that "appends" the new data to the previous data.
Now that you have an array of bytes, you can start looking for your message, and you don't have to convert the numbers to strings.
I'm tired and heading to bed, so some example of using the byte array would be like the code below, but I'm not going to exhaustively proof it, so there could be an error.
Not shown is getting the data into the buffer and updating "used" (which would be done by the serial data reader). Also didn't add a calculate checksum function to generate a checksum to compare to the checksum byte in the packet.
Code:


  Dim Buffer(1000) As Byte  'Array of bytes to use as a buffer
  Dim Used as Integer
  Dim Ptr as Integer

' Assume you've read and accumulated a number of bytes in Buffer, and set Used to the last index filled
  Private Function extractPacketFromBuffer(ByRef pkt() As Byte) As Boolean  'note pkt() passed by reference so we can redim
    Dim success As Boolean = True
    Dim looking As Boolean = True
    Dim payloadLen As Integer

    Do While (looking)
      If used > 4 Then                  'can't have have a packet with less than six bytes
        If Buffer(Ptr) = &HAA Then        '  If we've found an 0xAA then
          payloadLen = Buffer(Ptr + 4)            '    Get the packet payload length
          If used > 4 + payloadLen Then '    if we have enough bytes in the buffer for a full message then
            If Buffer(ptr + 5 + payloadLen) = &HAB Then

              ReDim pkt(payloadLen + 5)
              Array.Copy(Buffer, ptr, pkt, 0, payloadLen + 6)
              looking = False 'no longer looking
              success = True  'we have a packet
              Dim unProcessedIdx = ptr + 6 + payloadLen        'Determine the first buffer byte index after the packet extracted
              If used > unProcessedIdx Then                    'If there are extra unprocessed bytes in the buffer
                Array.Copy(Buffer, unProcessedIdx, Buffer, 0, used - unProcessedIdx)  'move all the unprocessed bytes to the front
                Ptr = 0 'point to the front of the buffer for next time
              End If
              used -= unProcessedIdx  'adjust the used count down to account for all the processed bytes removed
            End If
          Else  'not enough bytes in the buffer for a full message, so leave for now
            looking = False  'no longer looking for a packet
            success = False  'no packet found this time
          End If
        Else
          ptr += 1
        End If
      Else
        looking = False
        success = False
      End If
    Loop


    Return success

  End Function

  Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    Dim pkt() As Byte 'will be redimensioned by the function if a packet is retrieved
    If extractPacketFromBuffer(pkt) Then  'if we extracted a packet
      Debug.Print(pkt.Length)      'Parse the packet to extract data
    End If
  End Sub



All times are GMT -6. The time now is 06:45 AM.

Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Search Engine Optimisation provided by DragonByte SEO v2.0.15 (Lite) - vBulletin Mods & Addons Copyright © 2017 DragonByte Technologies Ltd.
All site content is protected by the Digital Millenium Act of 1998. Copyright©2001-2011 MAS Media Inc. and Extreme Visual Basic Forum. All rights reserved.
You may not copy or reproduce any portion of this site without written consent.