Description of the binary field is:
Caller number, expressed with compressed BCD code, and the surplus bits are filled with “0xF”
I have tried to print with struct format '16c'
and I get: ('3', '\x00', '\x02', '\x05', '\x15', '\x13', 'G', 'O', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff')
and if I use '16b'
i get (51, 0, 2, 5, 21, 19, 71, 79, -1, -1, -1, -1, -1, -1, -1, -1)
. And it is not correct, I should get phone number, and numbers above are invalid.
print struct.unpack_from('>16b', str(data.read()),offset=46)
Above is code that didn't work and I get invalid numbers. With what format should I unpack that 16 byte field and how to convert BCD code ?
Binary Coded Decimal Representation of a Decimal Number In the BCD number system, the binary weight of each digit increases by a factor of 2 as shown. Then the first digit has a weight of 1 ( 20 ), the second digit has a weight of 2 ( 21 ), the third a weight of 4 ( 22 ), the fourth a weight of 8 ( 23 ).
BCD numbers encode less information than binary numbers with the same number of bits, as 6 of 16 possible states are not used for each 4-bit BCD number. Mathematically, each BCD “bit” only encodes 10^(1/4) = 1.778 states, while each binary bit encodes 2 states.
a = b'\x12\x34\x5f'
def comp3_to_int(a):
b = a.hex()
c = int(b[0:len(b)-1])
if b[len(b)-1:] == 'd':
c = -c
return c
BCD codes work with 4 bits per number, and normally encode only the digits 0 - 9. So each byte in your sequence contains 2 numbers, 1 per 4 bits of information.
The following method uses a generator to produce those digits; I am assuming that a 0xF value means there are no more digits to follow:
def bcdDigits(chars):
for char in chars:
char = ord(char)
for val in (char >> 4, char & 0xF):
if val == 0xF:
return
yield val
Here I use a right-shift operator to move the left-most 4 bits to the right, and a bitwise AND to select just the right-most 4 bits.
Demonstration:
>>> characters = ('3', '\x00', '\x02', '\x05', '\x15', '\x13', 'G', 'O', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff')
>>> list(bcdDigits(characters))
[3, 3, 0, 0, 0, 2, 0, 5, 1, 5, 1, 3, 4, 7, 4]
The method works with the c
output; you can skip the ord
call in the method if you pass integers directly (but use the B
unsigned variant instead). Alternatively, you could just read those 16 bytes straight from your file and apply this function to those bytes directly without using struct.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With