locked
Convert char to byte

    Question

  • Hi,

    My application is reading in data from the serial port. The packet format uses 1 byte to tell the data length. The problem is as I am reading each byte in as a char when I try to get the value of the received character (using Asc(cRxd)) it only works up to values of 127, any bytes received that are over 127 are received as 63. I noticed that this was the default parity replace value, but I have parity.none set and I also changed the parity replace value. The received byte is always 63. I have tried reading the data using .ReadByte but this gives the same result - only works on values below 128. Can anyone shed some light on this problem?

    Thanks in advance

    Mark
    • Edited by Mark Dubo Monday, January 25, 2010 8:11 PM Clarification of problem
    Monday, January 25, 2010 4:37 PM

Answers

  • Agreeing with Acamar


        Private Function buildSend(ByVal s As String) As Byte()
            Dim b() As Byte

            Dim myEnc As System.Text.Encoding
            myEnc = System.Text.Encoding.GetEncoding("Windows-1252")
            Dim t() As Byte = myEnc.GetBytes(s) 'convert string to bytes
            Array.Resize(b, t.Length + 5)
            b(0) = 2 'STX
            b(1) = CByte(Asc("S")) 'S
            b(2) = CByte(t.Length) 'the length of the string
            Array.Copy(t, 0, b, 3, t.Length) 'copy converted string to return
            b(b.Length - 1) = 3 'EOT
            b(b.Length - 2) = calcCRC(b) 'CRC
            Return b
        End Function

        Private Function calcCRC(ByVal b() As Byte) As Byte
            Return 13
        End Function

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

            SP.PortName = "COM5" 'configured as loobpack

            'Byte(0) 0x02 'STX
            'Byte(1) 'S'     'Command byte as ascii
            'Byte(2) 0x03 'Size as binary (can be > 127)
            'Byte(3) '1'     'Data1 as ascii
            'Byte(4) '2'     'Data2 as ascii
            'Byte(5) '0'     'Data3 as ascii
            'Byte(6) 0x13 'CRC as binary (can be >127)
            'Byte(7) 0x03 'EOT as binary

            Dim b() As Byte = buildSend("120") '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

            SP.BaudRate = 19200
            SP.DtrEnable = True
            SP.Open()
            SP.Write(b, 0, b.Length) 'write the bytes

            'FOR TESTING ONLY!!!!!
            'wait for the bytes to be looped
            Do While SP.BytesToRead < b.Length
                Application.DoEvents()
            Loop

            'set up a receive buffer
            Dim rcv() As Byte = New Byte() {0, 0, 0}

            'make it the right size
            Array.Resize(rcv, SP.BytesToRead)
            'in case BytesToRead changes between resize and read used buffer length
            SP.Read(rcv, 0, rcv.Length)

            If rcv(0) = 2 AndAlso Chr(rcv(1)) = "S" Then 'STX S ?
                'yes
                'convert the bytes that are ascii to a string (chars)
                Dim s As String

                Dim myEnc As System.Text.Encoding
                myEnc = System.Text.Encoding.GetEncoding("Windows-1252")
                s = myEnc.GetString(rcv, 3, rcv(2))
                TextBox1.Text = s
            End If

            SP.Close()
        End Sub


    Looking for work - Zip 65101 http://www.vbforums.com/showthread.php?t=552774
    • Marked as answer by Mark Dubo Tuesday, January 26, 2010 12:27 AM
    Monday, January 25, 2010 11:50 PM
  • Thanks dbasnett. I think I follow most of that code.

    Thanks to everyone who has contributed.

    I have got it working using my original code sending with this:

            For j = 0 To 7
                If TB_Val(j).Text = "" Then
                    MsgBox("No value for byte" & j)
                    Exit For
                Else
                    sString += Chr(Val(TB_Val(j).Text))
                End If
            Next

            Form1.SerialPort1.Write(sString)


    And receiving with this:

           Dim biRx As Byte

           While SerialPort1.BytesToRead > 0
                biRx = SerialPort1.ReadByte()
                'ProcessData(sRx)
           End While


    What I needed to do was set the encoding to

    SerialPort1.Encoding = System.Text.Encoding.GetEncoding("windows-1252")

     

    Thanks to all who have spent time trying to help. I really appreciate it.

    Mark
    • Marked as answer by Mark Dubo Tuesday, January 26, 2010 12:27 AM
    Tuesday, January 26, 2010 12:22 AM

All replies

  • Try using Convert.ToInt32(cRxd)
    Monday, January 25, 2010 5:36 PM
  • Did you try something like that:

    ' Reading One Byte from the Serial Port Input Buffer
    Dim cRxd As Byte = SerialPort1.ReadByte()

    I expect that you received data as bytes, your range is from 0 to 255. So Byte type should be sufficient to hold your data.

    You can also use CByte (cRxd) to convert your data into byte data type which is much better way to use in Visual Basic to convert any type to Byte.

    Hope it helps


    Waleed El-Badry
    Teaching Assistant
    Faculty of Engineering
    Misr University for Science & Technology

    MCPD Logo Gold Partner
    Monday, January 25, 2010 6:24 PM
  • Welcome back Mark.


            'simulated receive.  byte 0 has length
            Dim b() As Byte = New Byte() {5, 72, 144, 76, 76, 79}
            Dim s As String
            Dim myEnc As System.Text.Encoding
            myEnc = System.Text.Encoding.GetEncoding("Windows-1252")
            s = myEnc.GetString(b, 1, b(0))

    Looking for work - Zip 65101 http://www.vbforums.com/showthread.php?t=552774
    Monday, January 25, 2010 7:51 PM
  • What is the code you are using to get the byte from the serial port buffer?  If you are using a command that reads the byte as a char then you will get the type of conversion problem that you have indicated.  Read the byte as a byte, and do not convert it to char at any point unless you know that it really is a character.  If you are only reading plain ASCII then all bytes that should be characters will be less than 128.  So if you have a length packet, read the corrrect number of bytes in the packet as bytes, convert to number (according to the data format in which the length is expressed) and then read the correct number of bytes as char to get the plain text.

    http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.readbyte.aspx
    The difference is that readbyte will return the byte as read, ReadChar will attempt to convert the byte to a character in the default character set.
    Monday, January 25, 2010 8:16 PM
  • Thanks for the replies guys.

    jinzai Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medalswhen I try that i get an error at runtime - FormatException was unhandled, Input string was not in a correct format


    Waleed El-BadryUsers MedalsUsers MedalsUsers MedalsUsers MedalsI did try cRxd = SerialPort1.ReadByte() but this gives me the same problem. I can only receive bytes of values up to 127, over 127 and I receive 63. I have just tried using CByte(cRxd) but this gives exactly the same result.


    dbasnett I am not sure exactly what this does - it appears to assign the byte array to s minus byte(0). If byte(0) was the length byte I would need to assign a variable the value 5. In this case it would work fine because the value is < 128.

    What seems like a simple problem has turned into quite a headache (If only I could do this in C!). Any other suggestions?

    Thanks again guys!

    Mark
    Monday, January 25, 2010 8:42 PM
  • What is the code you are using to get the byte from the serial port buffer?  If you are using a command that reads the byte as a char then you will get the type of conversion problem that you have indicated.  Read the byte as a byte, and do not convert it to char at any point unless you know that it really is a character.  If you are only reading plain ASCII then all bytes that should be characters will be less than 128.  So if you have a length packet, read the corrrect number of bytes in the packet as bytes, convert to number (according to the data format in which the length is expressed) and then read the correct number of bytes as char to get the plain text.

    http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.readbyte.aspx
    The difference is that readbyte will return the byte as read, ReadChar will attempt to convert the byte to a character in the default character set.

    Acamar, I have tried reading both with .ReadChar and .ReadByte - both give me the same problem. I am not reading in just plain ascii, some of the packet will be in ascii and some will be binary data - some of the binary data may exceed 127 and this is were I am getting problems.

    Thanks

    Mark
    Monday, January 25, 2010 8:55 PM
  • I would recommend reading the whole stream as a byte array, and converting only that part of the stream that you know is plain ASCII to char.

    Have you checked that you are not inadvertently converting the byte values to char at some stage of your processing?   You can build a smal diagnostic that displays the bytes as received in hex or integer.  If they are being received without the high order bit then that is a problem of the serial communication connection - eg, the number of data bits in the sending or receiving port configuration (7 instead of 8).

    But if you can confirm that readbytes is returning all 8 bits, then the problem is in some later processing, and that is almost certainly a conversion to char or string somewhere in the code.
    Monday, January 25, 2010 9:04 PM
  • I would recommend reading the whole stream as a byte array, and converting only that part of the stream that you know is plain ASCII to char.

    Have you checked that you are not inadvertently converting the byte values to char at some stage of your processing?   You can build a smal diagnostic that displays the bytes as received in hex or integer.  If they are being received without the high order bit then that is a problem of the serial communication connection - eg, the number of data bits in the sending or receiving port configuration (7 instead of 8).

    But if you can confirm that readbytes is returning all 8 bits, then the problem is in some later processing, and that is almost certainly a conversion to char or string somewhere in the code.

    It's not a processing problem - I am Debug.Printing the bytes as they come in before any processing takes place. The data bits are set to 8 and every byte that is sent that is 128 or more gets received as 63 - doesn't seem to matter what the actual value is as long as it is over 127. Strange indeed.

    Mark
    Monday, January 25, 2010 9:12 PM
  • What is the code you are using to receive the data and to debug print the byte values?

    If the data bits are 8 and you are using ReadByte to get the characters from the serial port buffer and if you are not accidentally converting to char or string then the problem mmust be in the sending system.

    The conversion to 63 (rather than just stripping the high bit) is exactly typical for processing a byte as a char or string using the default encoding (ASCII), either at the receiving end or at the transmitting end.

    Monday, January 25, 2010 9:18 PM
  • I am sending 8 bytes: {125, 126, 127, 128, 129, 130, 131, 132}

    When using this code:

    dim sRx As String
    
    While SerialPort1.BytesToRead > 0
                sRx = SerialPort1.ReadChar()
                Debug.Print("Val(sRx) = " & Val(sRx))
    
                'ProcessData(sRx)
            End While
    The output is:

    Val(sRx) = 125
    Val(sRx) = 126
    Val(sRx) = 127
    Val(sRx) = 63
    Val(sRx) = 63
    Val(sRx) = 63
    Val(sRx) = 63
    Val(sRx) = 63

    When i use the following code:

    Dim biRx As Byte
    
    While SerialPort1.BytesToRead > 0
                biRx = SerialPort1.ReadByte()
                Debug.Print("Val(biRx) = " & biRx)
    
                'ProcessData(sRx)
            End While
    The output is:

    biRx = 125
    biRx = 126
    biRx = 127
    biRx = 63
    biRx = 63
    biRx = 63
    biRx = 63
    biRx = 63


    Any ideas anyone??

    Monday, January 25, 2010 9:30 PM
  • The Val() function takes a string as an argument.  The compiler is doing a byte to char conversion for you and is applying the default encoding (ASCII).

    You need to display the byte value as integer or hex in order to find out what is actually being read from the port.

    Monday, January 25, 2010 9:45 PM
  • This works:

            Dim data() As Byte = {125, 126, 127, 128, 129, 130, 131, 132}
            For i As Integer = 0 To data.Length - 1
                Debug.Print("Value is actually :" & Convert.ToUInt16(data(i)))
            Next
    
    I think your error is on the transmit side....
    Monday, January 25, 2010 9:46 PM
  • The Val() function takes a string as an argument.  The compiler is doing a byte to char conversion for you and is applying the default encoding (ASCII).

    You need to display the byte value as integer or hex in order to find out what is actually be read from the port.


    Acamar - there was a mistake in the code I posted it should have read:  Debug.Print("biRx = " & biRx)
    Monday, January 25, 2010 9:58 PM
  • Acamar has a good point about the encoding. By default, it is ASCII, which has no valid character with a set MSB (i.e. No negative values allowed.)

    Try setting the SerialPort.Encoding to UTF-8

    Monday, January 25, 2010 10:02 PM
  • In that case I am not sure what result you will get when you try to print a byte, but I suspect exactly the same type of conversion will apply.  Don't print as double or byte or anything other than Integer or Hex.

    Read you serial port data as a byte array and print it like this:

               Debug.Print("(biR() = " & BitConverter.ToString(biR))

    Monday, January 25, 2010 10:04 PM
  • Welcome back Mark.


            'simulated receive.  byte 0 has length
            Dim b() As Byte = New Byte() {5, 72, 144, 76, 76, 79}
            Dim s As String
            Dim myEnc As System.Text.Encoding
            myEnc = System.Text.Encoding.GetEncoding("Windows-1252")
            s = myEnc.GetString(b, 1, b(0))

    Looking for work - Zip 65101 http://www.vbforums.com/showthread.php?t=552774

    Yes, you indicated some byte was the length, and I assumed it was followed by the data, that you seem to expect as characters.  By using the encoding I overcome the problem of bytes with values > 127.

    Looking for work - Zip 65101 http://www.vbforums.com/showthread.php?t=552774
    Monday, January 25, 2010 10:05 PM
  • This works:

            Dim data() As Byte = {125, 126, 127, 128, 129, 130, 131, 132}
    
            For i As Integer = 0 To data.Length - 1
    
                Debug.Print("Value is actually :" & Convert.ToUInt16(data(i)))
    
            Next
    
    
    
    
    I think your error is on the transmit side....

    When i try:

    While SerialPort1.BytesToRead > 0
                biRx = SerialPort1.ReadByte()
                Debug.Print("Value is actually :" & Convert.ToUInt16(biRx))
    
                'ProcessData(sRx)
            End While
    I get exactly the same result. So yes it may be on the transmit side. I am transmitting from the same program with pins 2 and 3 shorted - I debug.print the character values as they are sent and they are all correct. Like so:

    sending byte(0) = 125
    sending byte(1) = 126
    sending byte(2) = 127
    sending byte(3) = 128
    sending byte(4) = 129
    sending byte(5) = 130
    sending byte(6) = 131
    sending byte(7) = 132

    Value is actually :125
    Value is actually :126
    Value is actually :127
    Value is actually :63
    Value is actually :63
    Value is actually :63
    Value is actually :63
    Value is actually :63

    Monday, January 25, 2010 10:06 PM
  • Are you writing bytes or writing chars?  What is the sending code?
    Monday, January 25, 2010 10:10 PM
  • Are you writing bytes or writing chars?  What is the sending code?

    For debug/testing purposes I have a form with textbox's. The code reads the contents of the textboxes and builds a string.

            Dim j As Integer
            sString = ""
            For j = 0 To 7
                If TB_Str(j).Text = "" Then
                    If TB_Val(j).Text = "" Then
                        MsgBox("No value for byte" & j)
                        Exit For
                    Else
                        sString += Chr(Val(TB_Val(j).Text))
                        'Form1.SerialPort1.Write(Chr(TB_Val(j).Text))
                    End If
                Else
                    sString += TB_Str(j).Text
                    'Form1.SerialPort1.Write(Chr(TB_Val(j).Text))
                End If
                Debug.Print("byte(" & j & ") = " & Asc(sString(j)))
    
            Next
    
            Form1.SerialPort1.Write(sString)
    Monday, January 25, 2010 10:19 PM



  •         sp.PortName = "COM5" 'configured as loobpack
            Dim b() As Byte = New Byte() {125, 126, 127, 128, 129, 130, 131, 132}
            sp.BaudRate = 19200
            sp.DtrEnable = True

            sp.Open()

            sp.Write(b, 0, b.Length)

            'for testing only
            'wait for the bytes to be looped
            Do While sp.BytesToRead < b.Length
                Application.DoEvents()
            Loop

            'set up a receive buffer
            Dim rcv() As Byte

            'make it the right size
            Array.Resize(rcv, sp.BytesToRead)
            'in case BytesToRead changes between resize and read used buffer length
            sp.Read(rcv, 0, rcv.Length)

            'convert the bytes to a string (chars)
            Dim s As String

            Dim myEnc As System.Text.Encoding
            myEnc = System.Text.Encoding.GetEncoding("Windows-1252")
            s = myEnc.GetString(rcv, 0, rcv.Length)
            Debug.WriteLine(s)
            's = }~€�‚ƒ„
            For Each c As Char In s
                Debug.WriteLine("'" & Asc(c)) 'see below
            Next
            '125
            '126
            '127
            '128
            '129
            '130
            '131
            '132
            sp.Close()

    Looking for work - Zip 65101 http://www.vbforums.com/showthread.php?t=552774
    Monday, January 25, 2010 10:20 PM
  • Welcome back Mark.


            'simulated receive.  byte 0 has length
            Dim b() As Byte = New Byte() {5, 72, 144, 76, 76, 79}
            Dim s As String
            Dim myEnc As System.Text.Encoding
            myEnc = System.Text.Encoding.GetEncoding("Windows-1252")
            s = myEnc.GetString(b, 1, b(0))

    Looking for work - Zip 65101 http://www.vbforums.com/showthread.php?t=552774

    Yes, you indicated some byte was the length, and I assumed it was followed by the data, that you seem to expect as characters.  By using the encoding I overcome the problem of bytes with values > 127.

    Looking for work - Zip 65101 http://www.vbforums.com/showthread.php?t=552774

    Could you explain how the encoding works - I can't figure it out from looking at the code.
    Monday, January 25, 2010 10:22 PM
  • If you are using anything except .Read or .ReadByte an encoder sits between you and the serial port.  The default encoder converts bytes > 127 to 63(?).  Sound familiar?  You can also set the encoding for the port by setting the ports .Encoding property.


    Looking for work - Zip 65101 http://www.vbforums.com/showthread.php?t=552774
    Monday, January 25, 2010 10:26 PM
  • Is TB_Str the array of text box lines?

    Is Chr(TB_Val(j).Text the length byte?   If so,  then you should not be converting it to Char as that will apply the current encoding and create the problem.

    Put the length byte as byte. I can't tell how you would do that, as I'm not sure why it is the length.  How did the first character of TB_Val(j).Text get created?  It may be as simple as using Asc() instead of Chr().  However, since SerialPort.Write is overloaded I would prefer to see the value cast to a variable of the correct type (Byte()) and that variable used with the write command, instead of relying on the return value of the function.

    Then put the ASCII text as either byte() or string.

    Read the length byte as byte().  Read the ASCII text as either byte() or string.
    Monday, January 25, 2010 10:32 PM
  • If you expect to send and receive data with byte values > 127, why are you fooling with converting anything.  It would be very helpful if you described exactly what you intend to send, and exactly what you intend to receive, otherwise we could be at this for days.

    Looking for work - Zip 65101 http://www.vbforums.com/showthread.php?t=552774
    Monday, January 25, 2010 10:36 PM
  • Ok guys it is definately an encoding issue. An example packet is as follows:

    Byte(0) 0x02 'STX
    Byte(1) 'S'     'Command byte as ascii
    Byte(2) 0x03 'Size as binary (can be > 127)
    Byte(3) '1'     'Data1 as ascii
    Byte(4) '2'     'Data2 as ascii
    Byte(5) '0'     'Data3 as ascii
    Byte(6) 0x13 'CRC as binary (can be >127)
    Byte(7) 0x03 'EOT as binary

    I tried changing to UTF-8 but it converts values > 127 to 2 bytes
    Monday, January 25, 2010 10:53 PM
  • I should add that the data will be sent from a microcontroller, not from a windows machine.
    Monday, January 25, 2010 10:58 PM
  • The answer is Don't encode!   Avoid converting the length byte to a char or string, and you can ignore encoding.

    What type is TB-Val?  Why are you using it's Text property (that's one possibility for encoding).   If its already an integer, then convert directly to byte.

    Monday, January 25, 2010 11:02 PM
  • I thought that might be the case, which is why I usually don't try to help in these threads. I should've learned that last week.

    I will tell you that I don't use strings, or encoding at all. I treat the data like binary data, and that works so much better with this stuff. You see, in the "old days" it didn't matter...you used an unsigned byte. VB is much more strongly typed now, which makes these cute little string tricks fail - miserably. VB6 let you violate the rule about character values > 127, and VB6 creates an MBCS program, which makes all the difference.

    This is hardly the first thread that has gone this way...Someone has some old comm code that "Worked fine for 10 years", now they want to move it to .NET, and they begin coding it exactly like the other 10 year old event driven code, which is not even very easy to do in .NET

    .NET has an event driven model, and it does not "have" to consider those bytes to be characters at all. Those are decisions that get made to "expedite" the process.

    I have yet to see how this reduces the time to program over starting over in .NET with an event driven communications model.

    You can use ReadByte and Write, and avoid all of this nonsense...just get rid of the use of strings so close to the SerialPort...that's all. You will have to provide any line termination yourself, if that is required.
    Monday, January 25, 2010 11:08 PM
  • If you use the .Read method you can have the best of both.  Here is your example.  Please note that is what it is.


            SP.PortName = "COM5" 'configured as loobpack

            'Byte(0) 0x02 'STX
            'Byte(1) 'S'     'Command byte as ascii
            'Byte(2) 0x03 'Size as binary (can be > 127)
            'Byte(3) '1'     'Data1 as ascii
            'Byte(4) '2'     'Data2 as ascii
            'Byte(5) '0'     'Data3 as ascii
            'Byte(6) 0x13 'CRC as binary (can be >127)
            'Byte(7) 0x03 'EOT as binary

            Dim b() As Byte = New Byte() {2, 83, 3, 49, 50, 48, 13, 3} 'your example

            sp.BaudRate = 19200
            sp.DtrEnable = True
            SP.Open()
            SP.Write(b, 0, b.Length) 'write the bytes

            'FOR TESTING ONLY!!!!!
            'wait for the bytes to be looped
            Do While sp.BytesToRead < b.Length
                Application.DoEvents()
            Loop

            'set up a receive buffer
            Dim rcv() As Byte

            'make it the right size
            Array.Resize(rcv, SP.BytesToRead)
            'in case BytesToRead changes between resize and read used buffer length
            SP.Read(rcv, 0, rcv.Length)


            If rcv(0) = 2 AndAlso Chr(rcv(1)) = "S" Then 'STX S ?
                'yes
                'convert the bytes that are ascii to a string (chars)
                Dim s As String

                Dim myEnc As System.Text.Encoding
                myEnc = System.Text.Encoding.GetEncoding("Windows-1252")
                s = myEnc.GetString(rcv, 3, rcv(2))
            End If


            SP.Close()





    Looking for work - Zip 65101 http://www.vbforums.com/showthread.php?t=552774
    Monday, January 25, 2010 11:20 PM
  • TB-Val(0).Text = "125"
    TB-Val(1).Text = "126"
    :
    :
    TB-Val(7).Text = "132"

    I build the string with the following code:

            For j = 0 To 7
                If TB_Val(j).Text = "" Then
                    MsgBox("No value for byte" & j)
                    Exit For
                Else
                    sString += Chr(Val(TB_Val(j).Text))
                End If
            Next
    I read in with the following code:

           Dim biRx As Byte
    
           While SerialPort1.BytesToRead > 0
                biRx = SerialPort1.ReadByte()
    
                'ProcessData(sRx)
           End While
    Monday, January 25, 2010 11:22 PM
  • TB-Val(0).Text = "125"
    TB-Val(1).Text = "126"
    :
    :
    TB-Val(7).Text = "132"

    I build the string with the following code:

            For
     j = 0 To
     7
                If
     TB_Val(j).Text = ""
     Then
    
                    MsgBox("No value for byte"
     & j)
                    Exit
     For
    
                Else
    
                    sString += Chr(Val(TB_Val(j).Text))
                End
     If
    
            Next
    
    
    I read in with the following code:

           Dim
     biRx As
     Byte
    
    
           While
     SerialPort1.BytesToRead > 0
                biRx = SerialPort1.ReadByte()
    
                'ProcessData(sRx)
    
           End
     While
    
    

    Does that work?  What does ReadByte do?  Does it return a Byte type?  Do you want to process the received data one byte at a time?

    Looking for work - Zip 65101 http://www.vbforums.com/showthread.php?t=552774
    Monday, January 25, 2010 11:29 PM
  • No it still doesn't work. Without converting I am still getting the following values for the 8 bytes:

    biRx = 125
    biRx = 126
    biRx = 127
    biRx = 63
    biRx = 63
    biRx = 63
    biRx = 63
    biRx = 63

    Monday, January 25, 2010 11:34 PM
  • Are we doing this

            'Byte(0) 0x02 'STX
            'Byte(1) 'S'     'Command byte as ascii
            'Byte(2) 0x03 'Size as binary (can be > 127)
            'Byte(3) '1'     'Data1 as ascii
            'Byte(4) '2'     'Data2 as ascii
            'Byte(5) '0'     'Data3 as ascii
            'Byte(6) 0x13 'CRC as binary (can be >127)
            'Byte(7) 0x03 'EOT as binary

    or something else?  I provided an answer for the above.

    Looking for work - Zip 65101 http://www.vbforums.com/showthread.php?t=552774
    Monday, January 25, 2010 11:37 PM
  • If you are using

      TB_Val(j).Text

    then you are still converting.
    Monday, January 25, 2010 11:37 PM
  • Agreeing with Acamar


        Private Function buildSend(ByVal s As String) As Byte()
            Dim b() As Byte

            Dim myEnc As System.Text.Encoding
            myEnc = System.Text.Encoding.GetEncoding("Windows-1252")
            Dim t() As Byte = myEnc.GetBytes(s) 'convert string to bytes
            Array.Resize(b, t.Length + 5)
            b(0) = 2 'STX
            b(1) = CByte(Asc("S")) 'S
            b(2) = CByte(t.Length) 'the length of the string
            Array.Copy(t, 0, b, 3, t.Length) 'copy converted string to return
            b(b.Length - 1) = 3 'EOT
            b(b.Length - 2) = calcCRC(b) 'CRC
            Return b
        End Function

        Private Function calcCRC(ByVal b() As Byte) As Byte
            Return 13
        End Function

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

            SP.PortName = "COM5" 'configured as loobpack

            'Byte(0) 0x02 'STX
            'Byte(1) 'S'     'Command byte as ascii
            'Byte(2) 0x03 'Size as binary (can be > 127)
            'Byte(3) '1'     'Data1 as ascii
            'Byte(4) '2'     'Data2 as ascii
            'Byte(5) '0'     'Data3 as ascii
            'Byte(6) 0x13 'CRC as binary (can be >127)
            'Byte(7) 0x03 'EOT as binary

            Dim b() As Byte = buildSend("120") '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

            SP.BaudRate = 19200
            SP.DtrEnable = True
            SP.Open()
            SP.Write(b, 0, b.Length) 'write the bytes

            'FOR TESTING ONLY!!!!!
            'wait for the bytes to be looped
            Do While SP.BytesToRead < b.Length
                Application.DoEvents()
            Loop

            'set up a receive buffer
            Dim rcv() As Byte = New Byte() {0, 0, 0}

            'make it the right size
            Array.Resize(rcv, SP.BytesToRead)
            'in case BytesToRead changes between resize and read used buffer length
            SP.Read(rcv, 0, rcv.Length)

            If rcv(0) = 2 AndAlso Chr(rcv(1)) = "S" Then 'STX S ?
                'yes
                'convert the bytes that are ascii to a string (chars)
                Dim s As String

                Dim myEnc As System.Text.Encoding
                myEnc = System.Text.Encoding.GetEncoding("Windows-1252")
                s = myEnc.GetString(rcv, 3, rcv(2))
                TextBox1.Text = s
            End If

            SP.Close()
        End Sub


    Looking for work - Zip 65101 http://www.vbforums.com/showthread.php?t=552774
    • Marked as answer by Mark Dubo Tuesday, January 26, 2010 12:27 AM
    Monday, January 25, 2010 11:50 PM
  • Thanks dbasnett. I think I follow most of that code.

    Thanks to everyone who has contributed.

    I have got it working using my original code sending with this:

            For j = 0 To 7
                If TB_Val(j).Text = "" Then
                    MsgBox("No value for byte" & j)
                    Exit For
                Else
                    sString += Chr(Val(TB_Val(j).Text))
                End If
            Next

            Form1.SerialPort1.Write(sString)


    And receiving with this:

           Dim biRx As Byte

           While SerialPort1.BytesToRead > 0
                biRx = SerialPort1.ReadByte()
                'ProcessData(sRx)
           End While


    What I needed to do was set the encoding to

    SerialPort1.Encoding = System.Text.Encoding.GetEncoding("windows-1252")

     

    Thanks to all who have spent time trying to help. I really appreciate it.

    Mark
    • Marked as answer by Mark Dubo Tuesday, January 26, 2010 12:27 AM
    Tuesday, January 26, 2010 12:22 AM
  • I'm sorry, but that code is still wrong.

    What type is TB_Val()?  Why are you using the Text property of TB_Val(j), instead of the numeric value (I assume there is one, otherwise you wouldn't need to specify the Text property)?  Why are you converting the text to Char? If it's because you only want the first character of the string there are easier ways to do that, but it shouldn't be a string if it doesn't represent a character.  Do you know for sure that the encoding you are using will not do any character translation?

    If you weren't doing all these conversions you would not need to set the encoding.  I would be pretty confident that sending byte data as text, whatever encoding you choose, will come back to bite you in the future.



    Tuesday, January 26, 2010 12:43 AM
  • Acamar I am using the Val() function to get the numerical value of the string in the textbox before using the Chr() function to get the character associated with the numerical value then appending the character to the string.

    The reason i done it like this was as a quick (or so i thought) way to test my serial code and packet processing code. I have two sets of 8 text boxes, in one set I can enter 1 character - these are added to the string as is. The other set of textboxes I can add numbers - these are converted to characters as mentioned above.

    Note that this was purely as a mean of testing before I start to code the microcontroller, and as it is a microcontroller I know there won't be any encoding problems on the transmit side.

    Thanks for all the help.

    Mark
    Tuesday, January 26, 2010 1:08 AM
  • @Mark - a couple of points.

    1.  The first line of your program should be Option Strict On.  I know that it isn't because of this
            Dim biRx As Byte

            biRx = SerialPort1.ReadByte()

    2.  What is TB_Val?  It can't be a TextBox because this code won't even compile:

            For j = 0 To 7
                If TB_Val(j).Text = "" Then 'what is TB_Val??????????????????
                    MsgBox("No value for byte" & j)
                    Exit For
                Else
                    sString += Chr(Val(TB_Val(j).Text))
                End If
            Next

    3.  Acamar and I are both trying to guide you down a path that will keep you out of trouble down the road.  Just because you have something that works now doesn't mean you are making progress.  Statements like this  sString += Chr(Val(TB_Val(j).Text)) are odd.  First, it is good practice to use & for concatenation, not + .  Second, the statement appears to be saying convert a character to a number, then convert it back to a character?  Are you just converting for the fun of it?

    4.  When posting questions on the forum that concern SerialPorts, use the words Serial Port in the subject.  Like Serial Port convert char to byte.  There are three or four people that post that know serial communications, but may or may not see threads like this one.


    Good luck to you.

    Looking for work - Zip 65101 http://www.vbforums.com/showthread.php?t=552774
    Tuesday, January 26, 2010 2:28 PM
  • Hi dbasnett,

    1. You are right, I do not have that as the first line in my code. What does this do? Does it ensure strict adherence to types?

    2. TB_Val() is an array of TextBoxes created with the following code:

            For j = 0 To 7
                TB_Str(j) = New TextBox
                TB_Val(j) = New TextBox
                Y += 26
                TB_Str(j).Width = 40
                TB_Str(j).Height = 20
                TB_Val(j).Width = 40
                TB_Val(j).Height = 20
                TB_Str(j).Location = New Point(208, Y)
                TB_Val(j).Location = New Point(258, Y)
                Controls.Add(TB_Str(j))
                Controls.Add(TB_Val(j))
            Next j

    3. I know both you and Acamar are trying to help, and I appreciate the help and guidance. I know the & operator is the preferred option for concatenation and this is what I used in VB6 (long time ago), but when I first started this project, using VB 2008 for the first time I remember getting an error when I tried to use & for this. I realise now I must have used it wrong.

    I use the statement sString += Chr(Val(TB_Val(j).Text))  as I want to be able to set the value for any byte in the packet to any value between 0 and 255. So for example I can type "147" into TB_Val(1) thus  Val(TB_Val(1)) passes the integer 147 to Chr() which returns the ascii code represented by 147. I couldnt think of any other way of being able to set the values of each individual byte. I'm certainly not converting just for fun!! :)

    4. Yes you are completely right - next time I will try to come up with a more suitable title.

    Thanks for the feedback and advice.

    Mark
    Tuesday, January 26, 2010 9:16 PM
  • I use the statement sString += Chr(Val(TB_Val(j).Text))  as I want to be able to set the value for any byte in the packet to any value between 0 and 255. So for example I can type "147" into TB_Val(1) thus  Val(TB_Val(1)) passes the integer 147 to Chr() which returns the ascii code represented by 147. I couldnt think of any other way of being able to set the values of each individual byte. I'm certainly not converting just for fun!! :)


    It's not the conversion as such that concerns me, although it can be simplified:

                Dim b(0) As Byte = CByte(Val(TB_Val(j).Text))
    

    It's this line:

    Form1.SerialPort1.Write(sString)

    If you are writing any binary data at all in that stream then you should not be writing a string.  It will turn round and bite you down the track for sure. Binary data cannot be reliably written to the serial port using the string form of the .Write method.   Either split the text and the binary data and write them separately, or write the whole stream as binary data.

    Option Strict On will tell you when the compiler is being forced to do an implicit type conversion behind the scenes.  It is a warning that something you don't expect might be happening.   So you are forced to make the conversion explicit, and presumably that requires you to check that the conversion will work properly.  It doesn't prevent you from doing the conversion - it simply forces you to make it explicit. 

    It won't tell you that you are using the wrong method to write the data;)

    Tuesday, January 26, 2010 9:53 PM
  • Mark posted this


            'Byte(0) 0x02 'STX
            'Byte(1) 'S'     'Command byte as ascii
            'Byte(2) 0x03 'Size as binary (can be > 127)
            'Byte(3) '1'     'Data1 as ascii
            'Byte(4) '2'     'Data2 as ascii
            'Byte(5) '0'     'Data3 as ascii
            'Byte(6) 0x13 'CRC as binary (can be >127)
            'Byte(7) 0x03 'EOT as binary


    If his intent is to send this, a mixture of byte data i.e. STX, EOT, CRC!! and string data then I agree with acamar.  One of my posts show how you mix the data and use SerialPort1.Write bufferAsByte....

    Well, Mark has something that works, and if he has problems in the future we can always reference this thread.
    Looking for work - Zip 65101 http://www.vbforums.com/showthread.php?t=552774
    Tuesday, January 26, 2010 11:58 PM
  • Acamar/dbasnett

    I understand both your concerns, however my program will not be using Form1.SerialPort1.Write(). It will only ever be receiving data. The data will be sent from an 8-bit microcontroller inside a Vital Signs Patient monitor. All the code in the monitor is in C and I don't need to worry about encoding on the transmit side. I was using the code above purely to quickly test my packet processing code - it will be removed after testing.

    Now on to the next problem.... :)
    Wednesday, January 27, 2010 1:01 PM
  • I apologize for being away all that long. Overloaded as usual :-)

    I see that Acmar and dbasnett are doing great job as expected.

    I carried out several projects using PIC Micro-controller (12Fxxx,16FXXX,18Fxxx). I used MikroBASIC compiler and had no problems in implementing full duplex data transfer. I used Bytes to perform the data transfer without any problems.

    Any way, it was a very good thread. Well done all of you.

     
    Waleed El-Badry
    Teaching Assistant
    Faculty of Engineering
    Misr University for Science & Technology

    MCPD Logo Gold Partner
    Wednesday, January 27, 2010 10:11 PM