May 09, 2024, 07:18:06 AM

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


Hex to binary.

Started by Egil, June 06, 2009, 12:36:55 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Egil

June 06, 2009, 12:36:55 PM Last Edit: June 06, 2009, 12:38:30 PM by Egil
A friend and myself was so inspired by this article published by a radio amateur in Luxembourg that we decided to make our own version:

http://www.lll.lu/~edward/edward/adsb/SimpleAdbsReceiver.html

While waiting for some hard to get electronic parts to arrive, I have started to program my own conversion routines, so I can show plane positions on a map. I will use the same Atmel microcontroller and use the same software as in the mentioned article. So the output will be similar to what Edward achieved.
The data produced by the decoder consist of databursts 28 characters long, each burst representing a bitstream of 112 bits. I am now testing my version of a hex to binary routine:
'------------------------------------------------------------------------------
' Convert hex characters to "binary strings"
'
SUB HexToBin(string c),string
DEF tbits,bits:string
DEF i:int
bits = ""
tbits = ""
FOR i = 1 to LEN(c)
if mid$(c,i,1) = "0" THEN tbits = "0000"
if mid$(c,i,1) = "1" THEN tbits = "0001"
if mid$(c,i,1) = "2" THEN tbits = "0010"
if mid$(c,i,1) = "3" THEN tbits = "0011"
if mid$(c,i,1) = "4" THEN tbits = "0100"
if mid$(c,i,1) = "5" THEN tbits = "0101"
if mid$(c,i,1) = "6" THEN tbits = "0110"
if mid$(c,i,1) = "7" THEN tbits = "0111"
if mid$(c,i,1) = "8" THEN tbits = "1000"
if mid$(c,i,1) = "9" THEN tbits = "1001"
if mid$(c,i,1) = "A" THEN tbits = "1010"
if mid$(c,i,1) = "B" THEN tbits = "1011"
if mid$(c,i,1) = "C" THEN tbits = "1100"
if mid$(c,i,1) = "D" THEN tbits = "1101"
if mid$(c,i,1) = "E" THEN tbits = "1101"
if mid$(c,i,1) = "F" THEN tbits = "1111"
bits = bits + tbits
NEXT i
RETURN bits
ENDSUB


But even if it appears to work ok, I feel it can be done in a more appropriate way. I will be grateful for any suggestions.
I enclose a zippped archive containing a log file with the same type of data I am trying to convert, and a source file for testing the conversion sub.
Support Amateur Radio  -  Have a ham  for dinner!

LarryMc

what I would try is:
read the line and strip the * as you are doing
prepend a "0x" to the string above
int mynumber = val(the string)

then call this sub by Bevets(rip) with your number and a base of 2
Sub ToBase(intValue As Int,Base As Int),String
   Dim result As String
   Dim i As Int
   result = ""
   If (base >= 2) & (base <= 36)
      While intValue > 0
         i = (intValue % base) + 1
         intValue = intValue / base
         result = Mid$("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",i,1)+result
      EndWhile
   EndIf
   Return result
EndSub


I don't know which is faster but if tackled with your problem this is what I would have done.

as you can see this sub will convert an int into a string in any base from 2 to 36)

Larry
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Ionic Wind Support Team

Larry,
but his hex isn't a "quantity" and it probably represents text.  His routine just takes the hex ASCII digits and converts them into a text binary representation.

"FEFE" = "1111111011111110"

Paul.

Ionic Wind Support Team

LarryMc

LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Egil

Paul is right Larry, in this phase of the decoding process all I have to do is to make a long "text-string" of the bit pattern.
But since english is not my mother tongue, it is sometimes difficult to express what I mean. Especially in connection with technical matters like this.

Later on I have to extract values from certain bitpatterns. There are numerous datatypes in the system, all have different bitpatterns, and only five or six of them are of interrest to me.  But to get access to them I first have to make this long string. And even though the result is correct (I have done some manual decoding to check), I have a feeling that I am doing it in an ackward way and wonder if there is another way to do it.

I tell you both, now that I finally start to get the grips of EB, I haven't had so much fun since I was a little  boy... :D ;D
Support Amateur Radio  -  Have a ham  for dinner!

celphick

Egil,
there is a slight error in your code. The line

if mid$(c,i,1) = "E" THEN tbits = "1101"     

should read

if mid$(c,i,1) = "E" THEN tbits = "1110"

and assuming that you have error checking to allow no other characters such as lower case you could try this variation.

'------------------------------------------------------------------------------
' Convert hex characters to "binary strings"
'
SUB HexToBin(string c),string
string a = "0123456789ABCDEF"
string b = "0000000100100011010001010110011110001001101010111100110111101111"
string bits = ""
int i

FOR i = 1 to LEN(c)
bits = bits + mid$(b,4*instr(a,mid$(c,i,1))-3,4)
NEXT i
RETURN bits
ENDSUB


It looks shorter but that doesn't mean that it will compile as a faster or smaller program.

Colin.


Egil

Thanks for correcting me Colin!
Didn't see that myself. Guess I would have had problems finding that one while testing the system i real time...

Error trapping is further down on my todo-list, but didn't plan to do it until I have got the last piece of information needed to fully understand how the datapackets are built. The only missing detail now, is how they produce the checksum, which is the last 24 bits in each packet.

I will try your code and compare.
Support Amateur Radio  -  Have a ham  for dinner!

Ficko

Hi Egil!

I attached a little lib with full source has 2 funktions (BIN$ and VALHEX) to do the conversion.

Regards,
Ficko

Egil

Support Amateur Radio  -  Have a ham  for dinner!

Egil

Ficko:
Your library will certainly come in handy later on in my project, so I thank you for sharing.
But in this particular instance I just want to convert each character in a "hex-string" to a binary bitmap.

celphick:
I inspected the asembler code. My original version of HexToBin poduced 743 lines of code, while your version only has 144 lines. That is an 80% reduction, so I am quite sure the final execution speed wil be faster.
Support Amateur Radio  -  Have a ham  for dinner!

sapero

This is my inline version (only 41 lines) with buffer overflow protecton and case insensitive:
declare HexToBin(string szHex, /*out*/string szBin, int cchBin)
istring szBin[256]

HexToBin("0123456789ABCDEFabcdef", szBin, 256)
messagebox 0, szBin,""

' somewhere in your eba file
_asm
jmp endofasm ; required in ebasic
HexToBin: ; (char *szHex, char *szBin, int cchBin)
xchg esi, [esp+4]  ; szHex
mov  edx, [esp+8]  ; szBin
mov  ecx, [esp+12] ; cchBin
h2bgo:
cmp   ecx,5
jb    h2bfinalize    ; no space in output string
movzx eax,byte[esi]  ; get the next character from input string
add   esi,1
test  al,al
jz    h2bfinalize    ; break if end of input string
sub   al,'0'         ; skip characters below "0"
jc    h2bgo
cmp   al,'f'-'0'     ; skip characters above "f"
jg    h2bgo
movzx eax,byte[h2bo+eax] ; get the offset of 4digit binary form in h2bbin array
cmp   al,1
je    h2bgo           ; skip if character is :;<=>?@GHIJKLMNOPQRSTUVWXYZ[\]^_`
mov   eax,[h2bbin+eax]; get the four binary digits from bit table
mov   [edx],eax       ; and append to output string
add   edx,4           ; update append position
sub   ecx,4           ; and size of output string
jmp   h2bgo
h2bfinalize:
cmp   ecx,1          ; check if there is space for terminating NULL
jb    h2bquit
mov   byte[edx],0
h2bquit:
xchg esi, [esp+4]
ret  12

; value 1 is invalid - to detect invalid hex digits
h2bo: db 0,4,8,12,16,20,24,28,32,36 ; digits '0' - '9'
      db 1,1,1,1,1,1,1
      db 40,44,48,52,56,60 ; A-F
      db 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1 ; 26 idle characters
      db 40,44,48,52,56,60 ; a-f

align 4 ; force DWORD alignment to read 4 digit at a time faster
h2bbin:  db "0000000100100011010001010110011110001001101010111100110111101111"
endofasm:
_endasm


The first instruction (jmp endofasm) can be removed if you add END before _asm.

Egil

Thanks Sapero!
Many years ago (25 - 30) I did programming for a local company, all assembler. But when I was offered a better paid job in the maintenance department I accepted.
That was the end of my programming career... But when I retired, i started with Emergence Basic just for fun. But the learning process have been ratrher slow.
And when I try to  follow your assembler code today, I understand absolutly nothing! All is gone...
Maybe I should start learning assembler again as well... But not before I have become more confident with EB.
Support Amateur Radio  -  Have a ham  for dinner!

Ficko

June 08, 2009, 01:57:30 AM #12 Last Edit: June 08, 2009, 06:51:04 AM by Ficko
Hi Egil,

Quote
I just want to convert each character in a "hex-string" to a binary bitmap.

I don't really see any probleme to send only one character like "E" to the routines either mine or Saperos.

I use an "indirect way" to produce binary represantation.
First "Hex to Decimal" than "Decimal to Bin" because I had this two routines at hand and designed for EBasic.

BIN$ can be feed with all 32 and 64 bit types Ebasic has and you will receive accordingly a 32 or 64-bit binary represantation if you use "Trim = 0".
The routine can be easily extended to handle the remaining 2 types (8 and 16) but you can just cut so many zeros you wan't from the left and use int not int64 to get less zeros back.

VALHEX works like a filter you can feed it even with deliminators like "FE0B-E000-A001" up to 64-bit.
-It's require at least PII because uses mmx-

Just keep going,
Ficko  8)

Egil

Hi Ficko,
Maybe I am a little slow, but when trying your code I was not able to figure out how to get each character to show as a four-bit string, with the leading zeroes included.
But as mentioned earlier I will use your code when I reach the point where parts of these strings will be extracted and converted to real values.

In case anybody want to know, here is an introduction to what we are trying to decode:  http://www.avionik.pl/pliki/ADS-B-dane-techniczne.pdf
Support Amateur Radio  -  Have a ham  for dinner!

Ficko

June 08, 2009, 05:29:20 AM #14 Last Edit: June 09, 2009, 01:35:34 AM by Ficko
It's not your fault Egil I didn't provide enough information -I was on the hurry.-
And my sample didn't focus on your needs either. ;)

There is the code you propably need:

$USE "Conversions.lib"
DECLARE EXTERN BIN$(Num:Anytype,OPT Trim=TRUE:Uint),String
DECLARE EXTERN VALHEX(HexNum:String),Uint64
OPENCONSOLE
FOR A = ASC("0") TO ASC("9")
PRINT HexToBin(CHR$(A))
NEXT A
DO:UNTIL INKEY$<>""

SUB HexToBin(Hex:String),String
DEF VH:INT
DEF Binary:STRING
VH = VALHEX(Hex)
Binary = BIN$(VH,0)
Binary = MID$(Binary,29)
RETURN Binary
ENDSUB


Like mentioned above BIN$ will provide you with a 32 or 64 digit binary string you feed it with 32/64 type accordingly.
So I feed it with 32(VH:INT) and cut 28.
It would work by feeding it with 64 and cut 60 too.
You can change the declaration "OPT Trim=TRUE:Uint" to "OPT Trim=FALSE:Uint" and you don't need "0" by "BIN$(VH,0)"

Thanks for the link it is interesting stuff. :D
I will go over it definitely.
I use to be a "Airplannavigationtechnician" und had repaired MIG-21, MI-8 and MI-24.

Egil

Thanks again Ficko! I will give your code another try.
But since my last posting I have been busy coding. Inspired by you and celphick I modified the sub to only accept numbers 0-9 and letters A-F and a-f.
I hope that is enough filtering as there already is a  checksum included in every transmission.

Here is what I came up with (standard EB code only... ;)):
'------------------------------------------------------------------------------
' Convert hex characters to "binary strings"
'
SUB HexToBin(string c),string
string a = "0123456789ABCDEFabcdef"
string b = "0000000100100011010001010110011110001001101010111100110111101111101010111100110111101111"
string bits = ""
int i
FOR i = 1 to LEN(c)
IF INSTR(a,MID$(c,i,1)) <> 0 ' ONLY characters in string a are accepted
bits = bits + MID$(b,4*INSTR(a,MID$(c,i,1))-3,4)
ENDIF
NEXT i
RETURN bits
ENDSUB


Ok with your MIG experience. When I was young I used to work for the "opposition", but for the Royal Norwegian Navy. But fortunately we all are "on the same side" here on the forum.
Support Amateur Radio  -  Have a ham  for dinner!

LarryMc

We've got a little bit of everything.
I worked Weapons Control Radar on F-4Cs and
ForwardLooking/Terrain Following Radar and Inertial Navigation on RF-4Cs

That was all eons agon.

Larry
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library