Question

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 ?

Was it helpful?

Solution

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.

OTHER TIPS

Python 3.x has this built-in for bytes objects.

>>> c = b'3\x00\x02\x05\x15\x13GO\xff\xff\xff\xff\xff\xff\xff\xff'
>>> c.hex()
'330002051513474fffffffffffffffff'

And back:

>>> c = "9F1A020840"
>>> bytes.fromhex(c)
b'\x9f\x1a\x02\x08@'
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top