# Android QuestionConvert HEX in ASCII

#### StarinschiAndrei

##### Active Member
Longtime User
Hi,
Is there any function that can convert hex 15e in 30 31 35 3E ?
I tried to use:
B4X:
``````dim val as string     '15e
Log(bc.HexFromBytes (bc.StringToBytes(val,"UTF8")))``````
but the result is : 313565

#### Erel

##### B4X founder
Staff member
Longtime User
The question is not clear. If I understand the input is 15e. What is the expected output?

#### StarinschiAndrei

##### Active Member
Longtime User
The question is not clear. If I understand the input is 15e. What is the expected output?
Hi, the input is 15e and output should be 30 31 35 3E

#### klaus

##### Expert
Longtime User
Very strange!
You have three characters in the input and you want four for the output !?
hex 15e gives 313565
and 30 31 35 3E gives 015>
So, what are you trying to do?

#### emexes

##### Expert
Hi, the input is 15e and output should be 30 31 35 3E

This will do what precisely what you've asked for (and more ;-) and might thus tease out whether that's actually what you want:

B4X:
``````Sub SingleDigitHexToDoubleDigitHex(SingleDigitHexString As String, DigitPrefix As String, MinDigits As Int) As String

Dim HexChar As String
Dim DoubleDigitHexString As String = ""
Dim NumDigits As Int = 0

For I = 0 To SingleDigitHexString.Length - 1
HexChar = SingleDigitHexString.SubString2(I, I+1).ToUpperCase    'would prefer CharAt, if only it would cast as a string
If "0123456789ABCDEF".Contains(HexChar) Then
DoubleDigitHexString = DoubleDigitHexString & DigitPrefix & HexChar
NumDigits = NumDigits + 1
Else
'not a valid hex digit, so do whatever seems appropropriate here
End If
Next

Do While NumDigits < MinDigits
DoubleDigitHexString = DigitPrefix & "0" & DoubleDigitHexString
NumDigits = NumDigits + 1
Loop

Return DoubleDigitHexString.Trim    'removes leading space (if DigitPrefix includes one as a separator)

End Sub

Sub Tester

Dim SingleDigitHexString As String
Dim DoubleDigitHexString As String

SingleDigitHexString = "15e"
DoubleDigitHexString = SingleDigitHexToDoubleDigitHex(SingleDigitHexString, " 3", 4)    'note DigitPrefix includes separator space

Log("input = " & SingleDigitHexString)
Log("output = " & DoubleDigitHexString)

End Sub``````

#### StarinschiAndrei

##### Active Member
Longtime User
Dear Klaus ,
I'm try to communicate with a device via Bluetooth based on the below protocol. I have to calculate BCC (position 6).

B4X:
``````Dim bc As ByteConverter
Dim bb As BytesBuilder
Dim bcc As Int
bb.Initialize
Dim c As String=""
Dim CMD() As String=Regex.Split(",",TXTMSG.Text)
bb.Append(Array As Byte(0x01))
bb.Append(Array As Byte(0x25))
bb.Append(bc.HexToBytes(Bit.ToHexString(Rnd(32,255))))
bb.Append (bc.HexToBytes("45"))

If CMD(4)="0" Then
bb.Append(bc.StringToBytes("0","UTF8"))
End If
bb.Append (bc.HexToBytes("05"))

Bit.ParseInt(bc.StringFromBytes(bb.SubArray2(3,4),"UTF-8") ,16)))
Dim pz1 As String=bc.HexFromBytes( bb.SubArray2(1,2))
Dim pz2 As String=bc.HexFromBytes( bb.SUBARRAY2(2,3))
Dim pz3 As String=bc.HexFromBytes( bb.SUBARRAY2(3,4))
Dim pz4 As String=bc.HexFromBytes( bb.SUBARRAY2(4,5))
Dim pz5 As String=bc.HexFromBytes( bb.SUBARRAY2(5,6))
Dim val As String=Bit.ToHexString( Bit.ParseInt(pz1,16)+Bit.ParseInt(pz2,16)+Bit.ParseInt(pz3,16)+Bit.ParseInt(pz4,16)+Bit.ParseInt(pz5,16))
Dim CF() As Byte=val.GetBytes("UTF8")
Log(CF.Length)
For I=0 To 3-CF.Length
bb.Append(bc.HexToBytes("30"))
Next
For J=0 To CF.Length-1
Log(CF(J))
'bb.Append(bc.HexToBytes(bc.StringToBytes( Chr(3)&CF(J),"utf8")))
Next
LBLCMD.Text=    bc.HexFromBytes(bb.ToArray)``````

#### emexes

##### Expert
Hey Andrei, turns out we're a lot closer to your solution than I thought. Bonus! In fact, the solution should be even simpler the one above, especially if we're allowed to assume that BCC is always 4 ASCII bytes long.

#### StarinschiAndrei

##### Active Member
Longtime User
Hey Andrei, turns out we're a lot closer to your solution than I thought. Bonus! In fact, the solution should be even simpler the one above, especially if we're allowed to assume that BCC is always 4 ASCII bytes long.
Hey emexes, thank you ! ! ! . I will try your code.

#### emexes

##### Expert
No, no... that's not code... THIS is code!

B4X:
``````'convert unsigned number 0..255 to signed byte -128..127 (sometimes I hate Java)
Sub UnsignedToSignedByte(X As Int) As Byte

If X > 0 And X < 255 Then
If X < 128 Then
Return X
Else
Return X - 256
End If
Else
'out of range, do whatever you have to do
End If

End Sub

'convert signed byte -128..127 to unsigned number 0..255
Sub SignedByteToUnsigned(X As Byte) As Int

'no need to check input range since all results fit within int

If X < 0 Then
Return X + 256
Else
Return X
End If

End Sub

Sub PacketForAndrei(Seq As Byte, Cmd As Byte, DataBytes() As Byte) As Byte()

Dim PacketLength As Int = 4 + DataBytes.Length + 6

Dim PacketBytes(PacketLength) As Byte

Dim PutPtr As Int = 0

'Position 1 = SOH
PacketBytes(PutPtr) = 0x01
PutPtr = PutPtr + 1

'Position 2 = LEN
PacketBytes(PutPtr) = UnsignedToSignedByte(0x20 + 3 + DataBytes.Length + 1)    'note offset by 0x20
PutPtr = PutPtr + 1

'Position 3 = SEQ
PacketBytes(PutPtr) = Seq
PutPtr = PutPtr + 1

'Position 4 = CMD
PacketBytes(PutPtr) = Cmd
PutPtr = PutPtr + 1

'Position 5 = DATA
For I = 0 To DataBytes.Length - 1    'sometimes I miss traditional BASIC's array indexing too...
PacketBytes(PutPtr) = DataBytes(I)
PutPtr = PutPtr + 1
Next

'Position 6 = post-amble
PacketBytes(PutPtr) = 0x05
PutPtr = PutPtr + 1

'Position 7 = BCC
Dim ControlSum As Int = 0
For I = 1 To PutPtr - 1    'Position 2 to Position 6
ControlSum = ControlSum + SignedByteToUnsigned(PacketBytes(I))
Next
'zero operations left in because computer time is cheap and programmer time is not
PacketBytes(PutPtr + 0) = 0x30 + Bit.And(Bit.ShiftRight(ControlSum, 12), 0x000F)
PacketBytes(PutPtr + 1) = 0x30 + Bit.And(Bit.ShiftRight(ControlSum,  8), 0x000F)
PacketBytes(PutPtr + 2) = 0x30 + Bit.And(Bit.ShiftRight(ControlSum,  4), 0x000F)
PacketBytes(PutPtr + 3) = 0x30 + Bit.And(Bit.ShiftRight(ControlSum,  0), 0x000F)
PutPtr = PutPtr + 4

'Position 8 = ETX
PacketBytes(PutPtr) = 0x03
PutPtr = PutPtr + 1

If PutPtr <> PacketBytes.Length Then
'well, this is embarrassing
End If

Return PacketBytes

End Sub

Sub Tester

Dim DataBytes(10) As Byte
For I = 0 To DataBytes.Length - 1
DataBytes(I) = 100 + I    'easy-to-see sample data
Next

Dim X() As Byte = PacketForAndrei(0x44, 0x55, DataBytes)

Dim Temp As String = "Returned " & X.Length & " bytes ="
For I = 0 To X.Length - 1
Temp = Temp & " " & X(I)
Next
Log(Temp)

End Sub``````

#### emexes

##### Expert
Returned 20 bytes = 1 46 68 85 100 101 102 103 104 105 106 107 108 109 5 48 52 62 49 3

I think we could be on the home stretch ;-)

#### emexes

##### Expert
BCC definition is a bit vague: "Sum of data bytes from position 2 to position 6."

(a) data bytes? as opposed to non-data bytes?? does that include the LEN, SEQ and CMD bytes???

(b) position 1 is unambiguously not included, but... position 6 is of fixed value like position 1, and thus also of no usefulness in BCC, so why include position 6 but not position 1?

If your BCC values aren't matching the manufacturer's examples (what do you mean, they haven't supplied any??? ;-/ ) then those would be the areas to first check.

#### StarinschiAndrei

##### Active Member
Longtime User
BCC definition is a bit vague: "Sum of data bytes from position 2 to position 6."

(a) data bytes? as opposed to non-data bytes?? does that include the LEN, SEQ and CMD bytes???

(b) position 1 is unambiguously not included, but... position 6 is of fixed value like position 1, and thus also of no usefulness in BCC, so why include position 6 but not position 1?

If your BCC values aren't matching the manufacturer's examples (what do you mean, they haven't supplied any??? ;-/ ) then those would be the areas to first check.
Thank you ... i will give you some details regarding the communication (unfortunately i can't upload the entire doc because is confidential). I monitored the serial port (manufacturer app + device under windows) the sent command was : 01 25 F8 45 30 05 30 31 39 37 03 ; 01 25 D1 45 30 05 30 31 37 30 03, etc.
I created an array manually
B4X:
`` AStream.Write(Array As Byte(0x01, 0x25, 0xD1, 0x45, 0x30, 0x05, 0x30, 0x31, 0x37, 0x30, 0x03 ))``
worked fine. Now i should reproduce the same array programmatically. The array looks like this, now : 01253E4530053030. i thik the first code that you post is much better, the second one i couldn't test it.

#### emexes

##### Expert
The second code is better, because by then I had a bigger-picture view of where you were headed. And the reason I jumped on to it is: I have done a ton of serial interfacing in the past with protocols that look eerily similar to what you posted.

When you say you couldn't test it, does that mean it doesn't run on your computer, or that you're away from your workbench, or... ? I ran it here, and it generated a reasonable-looking packet. I cheerfully admit that I could easily be off-by-one somewhere with the length or something, but hey, I'm sure you love a good puzzle to keep you entertained at work, don't want to keep all the fun to myself ;-)

In fact, I've just had a brilliant thought, if the above sample you posted is an actual real correct packet. Will be back soon.

Last edited:

#### emexes

##### Expert
First the good news:

** Activity (main) Create, isFirst = true **
Returned 11 bytes = 01 25 F8 45 30 05 30 31 39 37 03
Returned 11 bytes = 01 25 D1 45 30 05 30 31 37 30 03
** Activity (main) Resume **

#### emexes

##### Expert
There is no bad news ;-)

The PacketForAndrei routine is unchanged. The test routine did change, (i) to test against the logged packets you gave, and (ii) to dump the results in hex rather than decimal, to make it easier to compare the regenerated packets against the original logs.

B4X:
``````Sub PacketDumper(X() As Byte)

Dim Temp As String = "Returned " & X.Length & " bytes ="

For I = 0 To X.Length - 1
Temp = Temp & " " & bc.HexFromBytes(Array As Byte(X(I)))
Next
Log(Temp)

End Sub

Sub Tester

'using actual recorded packets - let's see if we can reproduce it
'01 25 F8 45 30 05 30 31 39 37 03 ; 01 25 D1 45 30 05 30 31 37 30 03

'first packet is SEQ = F8, CMD = 45, DATA = 30

Dim DataBytes() As Byte = Array As Byte (0x30)
Dim X() As Byte = PacketForAndrei(0xF8, 0x45, DataBytes)
PacketDumper(X)

'second packet is SEQ = D1, CMD = 45, DATA = 30

'same data as previous = no need to create again
Dim X() As Byte = PacketForAndrei(0xD1, 0x45, DataBytes)
PacketDumper(X)

End Sub``````

#### StarinschiAndrei

##### Active Member
Longtime User
There is no bad news ;-)

The PacketForAndrei routine is unchanged. The test routine did change, (i) to test against the logged packets you gave, and (ii) to dump the results in hex rather than decimal, to make it easier to compare the regenerated packets against the original logs.

B4X:
``````Sub PacketDumper(X() As Byte)

Dim Temp As String = "Returned " & X.Length & " bytes ="

For I = 0 To X.Length - 1
Temp = Temp & " " & bc.HexFromBytes(Array As Byte(X(I)))
Next
Log(Temp)

End Sub

Sub Tester

'using actual recorded packets - let's see if we can reproduce it
'01 25 F8 45 30 05 30 31 39 37 03 ; 01 25 D1 45 30 05 30 31 37 30 03

'first packet is SEQ = F8, CMD = 45, DATA = 30

Dim DataBytes() As Byte = Array As Byte (0x30)
Dim X() As Byte = PacketForAndrei(0xF8, 0x45, DataBytes)
PacketDumper(X)

'second packet is SEQ = D1, CMD = 45, DATA = 30

'same data as previous = no need to create again
Dim X() As Byte = PacketForAndrei(0xD1, 0x45, DataBytes)
PacketDumper(X)

End Sub``````
THANK YOU ! ! ! YOU ARE AMAZING ! ! ! ... I will test in an hour when i arrive home.

#### emexes

##### Expert
Testing? What testing? That code is solid as a rock, we don't need no testing...

(Famous Last Words)

#### StarinschiAndrei

##### Active Member
Longtime User
Testing? What testing? That code is solid as a rock, we don't need no testing...

(Famous Last Words)
Thank you ! it works perfect.

#### emexes

##### Expert
No worries, it was kinda fun to do that stuff again. I probably spent a couple of days massaging my first packet send/receive routines into shape the first time I did it, so if I've saved you a bit of that same time and heartache, then we're good.

I was mulling over that you might be about to enter the packet-receive swamp (if you're not already knee-deep with those alligators ;-) and the first thing I'd do is pull out the checksum calculation into its own sub so that you can use it for both generating outgoing checksums and checking incoming checksums, eg:

B4X:
``````Sub CalculateChecksum(PacketBytes() As Byte, I1 As Int, I2 As Int) As Byte()

Dim ControlSum As Int = 0
For I = I1 To I2
ControlSum = ControlSum + SignedByteToUnsigned(PacketBytes(I))
Next

Dim ChecksumBytes(4) As Byte
'zero shift right left in because computer time is cheap and programmer time is not
ChecksumBytes(0) = 0x30 + Bit.And(Bit.ShiftRight(ControlSum, 12), 0x000F)
ChecksumBytes(1) = 0x30 + Bit.And(Bit.ShiftRight(ControlSum,  8), 0x000F)
ChecksumBytes(2) = 0x30 + Bit.And(Bit.ShiftRight(ControlSum,  4), 0x000F)
ChecksumBytes(3) = 0x30 + Bit.And(Bit.ShiftRight(ControlSum,  0), 0x000F)

Return ChecksumBytes

End Sub``````

and then the packet assembly bit collapses down to:

B4X:
``````'Position 7 = BCC
Dim ChecksumBytes() As Byte = CalculateChecksum(PacketBytes, 1, PutPtr - 1)    'Position 2 to Position 6
For I = 0 To 3
PacketBytes(PutPtr) = ChecksumBytes(I)
PutPtr = PutPtr + 1
Next``````

and on the disassembly side you'd have something like:

B4X:
``````'Position 7 = BCC
Dim ChecksumBytes() As Byte = CalculateChecksum(PacketBytes, 1, ChecksumPosition - 1)    'Position 2 to Position 6
Dim ChecksumOkFlag As Boolean = True    'optimism reigns supreme
For I = 0 To 3
If PacketBytes(ChecksumPosition + I) <> ChecksumBytes(I) Then
ChecksumOkFlag = False
Exit
End If
Next``````

BTW I did see you were using strings originally, which I can understand as a sin committed in the heat of the coding battle ;-) but the performance hit is like 100-fold or more. If you want to make it out of this low-level swamp alive, best avoid strings like the plague. Use bytes instead, or if the signed-vs-unsigned stuff gets too annoying, use shorts instead (still signed, but able to handle full "proper" 8-bit range 0..255) and convert them at handover to/from the serial stream. The maximum packet size was under 255 bytes, so worst-case is you waste maybe 500 bytes to have your packet assembly/disassembly buffers as easy-to-use shorts instead of pita bytes. Cheap insurance if you ask me, and you probably even reclaim some of that space through smaller/simpler code in that area.

What could possibly go wrong?!?!

Last edited:

Android Question HexFromBytes Error
Replies
1
Views
338
Android Code Snippet [B4X] Hex string to number
Replies
0
Views
3K
Android Code Snippet [B4X] HexToColor and ColorToHex
Replies
6
Views
5K
Android Question Convert AsciiHex to Binary
Replies
2
Views
1K
Replies
1
Views
4K