Hi Dave! In amateur radio we have a server that converts 7 digit numbers to shorter numbers based on the last 16 bits of their binary value. This is due to a 65518 number limit in NXDN. I would like to add the numbers to the database to display the correct call sign. Help!
I have to admit, this one took some back and forth communication to fully understand. Here’s the deal: Amateur radio (also known as ham radio) is built atop some pretty old school computer tech, so there are lots of 60’s and 70’s era elements. One of which is the continued reliance on 16-bit numerical call signs. Why 16-bits? Because that’s the double-byte integer storage capacity: 16 on/off slots. A single byte is just 8 binary values, and has a range of 0-256. 16-bits gets you 0-65535 (not 65518). You can calculate these yourself: 2**8 and 2**16.
Modern 32-bit systems have a considerably bigger MAXINT of 4,294,967,296 and if you’re writing a 64-bit program, your maximum integer value might be a whopping 1.844674407E19. Be that as it may, however, a question is a question, so let’s dig in…
I’m going to solve all of this as a Linux shell script but since it’s using basic scripting (with one exception) it’ll work fine in Windows or Mac if you can get to the Bash shell. Don’t have a Bash shell but have /bin/sh? You’ll need to tweak one line, but I’ll identify that shortly.
Here’s some sample input and output: Given 5054035 that should convert to 7763. How? By converting 5054035 to binary -> 10011010001111001010011, then chopping off the last 16 digits -> 0001111001010011 and then converting that back from binary into decimal.
That’s exactly how the script will work too.
First off, most conversions from one base to another can be easily accomplished in the powerful bc command:
longbinary="$(echo "obase=2;$1" | bc)"
Remember that $( … ) is a subshell, so we’re converting the given value – $1 – and saving it in the variable longbinary. Next step is to chop the last 16 digits off, and that’s done with a nifty trick: reverse the binary number, cut off the first 16 digits, then reverse it again to restore the proper order. Easier than figuring out the last n characters of a sequence:
last16="$(echo $longbinary | rev | cut -c1-16 | rev)"
And, finally, to convert that binary value back to decimal, let’s utilize an obscure Bash notational convention:
The $(( … )) loads the mathematics system in Bash, then 2# as a prefix indicates the value given is base 2, or binary. By default, it converts from binary to decimal, and voila! the solution.
I’ll put it all together in a script:
#!/bin/sh # given a long HAM radio identifier, convert it to binary # then grab the last 16 digits and convert that back to decimal if [ -z "$1" ] ; then echo "Usage: $0 RadioIdentifier" ; exit 1 fi longbinary="$(echo "obase=2;$1" | bc)" last16="$(echo $longbinary | rev | cut -c1-16 | rev)" result="$((2#$last16))" echo "input : $1" echo "in binary: $longbinary" echo "last 16 : $last16" echo "result : $result" exit 0
And that’s it. Now on the command line it’s easy to convert from those long amateur radio values to a digital call sign:
$ ham16.sh 5054035 input : 5054035 in binary: 10011010001111001010011 last 16 : 0001111001010011 result : 7763
Not too tricky once you understand the problem, right?
Want to learn more about amateur radio? No better place to start than ARRL, the national association for amateur radio!
Pro Tip: I’ve written quite a bit about how to solve complex problems with Linux shell scripts. While you’re here, please check out my linux shell script help area for lots more tutorials!