Search code examples
pythonbit-manipulationconcatenationbit-shift

Join two hex integers in Python


I am only new to Python, and currently reading 2 bytes from a digital compass using I2C on the Raspberry Pi. The MSB and LSB values are being stored in an array e.g.
a = [0x07, 0xFF]

I would like to join these two bytes into one variable such as
b == 0x07FF

How would I go about doing this?
I thought it would be as easy as multiplying the MSB by 256 and adding it to the LSB but I keep getting "IndexError: list index out of range"
Any help on this would be appreciated :)

My code is:

import smbus
import time

bus = smbus.SMBus(1)

addr = 0x1E

bus.write_byte_data(addr, 0x00, 0x70)
bus.write_byte_data(addr, 0x01, 0xA0)
bus.write_byte_data(addr, 0x02, 0x00)
time.sleep(0.006)

for i in range(0,10):
    x = bus.read_i2c_block_data(addr,0x03,2)
    y = bus.read_i2c_block_data(addr,0x07,2)
    z = bus.read_i2c_block_data(addr,0x05,2)

    xval = 256*x[2]+x[1]
    print x, y, z
    print xval
    time.sleep(1)
print 'exiting...'

The error I get is:

Traceback (most recent call last):
  File "compass2.py", line 18, in <module>
    xval = 256*x[2]+x[1]
IndexError: list index out of range

Solution

  • As noted in a comment, in Python, indexing begins at 0, not at 1. In your code, start at x[0], not x[1].

    To merge two integers from 0 to 255:

    Using bitwise

    Credit: this answer

    MAXINT = 255  # Must be a power-of-two minus one
    NUM_BITS = MAXINT.bit_length()
    
    def merge(a, b):
        c = (a << NUM_BITS) | b
        return c
    
    def split(c):
        a = (c >> NUM_BITS) & MAXINT
        b = c & MAXINT
        return a, b
    
    # Test:
    EXPECTED_MAX_NUM_BITS = NUM_BITS * 2
    for a in range(MAXINT + 1):
        for b in range(MAXINT + 1):
            c = merge(a, b)
            assert c.bit_length() <= EXPECTED_MAX_NUM_BITS
            assert (a, b) == split(c)
    

    Using arithmetic

    This technique works but is not preferred.

    MAXINT_PLUS1 = 256
    
    def merge(a, b):
        c = MAXINT_PLUS1 * a + b
        return c
    
    def split(c):
        a, b = divmod(c, MAXINT_PLUS1)
        return a, b
    
    # Test:
    EXPECTED_MAX_NUM_BITS = (MAXINT_PLUS1 - 1).bit_length() * 2
    for a in range(MAXINT_PLUS1):
        for b in range(MAXINT_PLUS1):
            c = merge(a, b)
            assert c.bit_length() <= EXPECTED_MAX_NUM_BITS
        assert (a, b) == split(c)