Python how to decode binary coded decimal (BCD)

Description of the binary field:

Caller number expressed in compressed BCD code and redundant bits are filled with "0xF"

I tried to print using the struct '16c' format, 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 this is not true, I have to get a phone number, and the numbers above are not valid.

 print struct.unpack_from('>16b', str(data.read()),offset=46) 

Above is code that doesn't work, and I get invalid numbers. What format should I unpack this 16-byte field with and how to convert the BCD code?

+9
source share
2 answers

BCD codes work with 4 bits per number and usually only encode the digits 0 - 9. Thus, each byte in your sequence contains 2 numbers, 1 for 4 bits of information.

The following method uses a generator to create these numbers; I assume that a value of 0xF means that there are no more digits:

 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 the shift operator to the right to move the leftmost 4 bits to the right, and the bitwise AND to select only the rightmost 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 output c ; you can skip the ord call in the method if you pass integers directly (but use unsigned option B instead). Alternatively, you can simply read these 16 bytes directly from your file and apply this function to these bytes directly without using a struct.

+17
source

Python 3.x has built-in byte 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@ ' 
0
source

Source: https://habr.com/ru/post/921400/


All Articles