28

I have a byte (from some other vendor) where the potential bit masks are as follows:

value1 = 0x01 value2 = 0x02 value3 = 0x03 value4 = 0x04 value5 = 0x05 value6 = 0x06 value7 = 0x40 value8 = 0x80

I can count on ONE of value1 through value6 being present. And then value7 may or may not be set. value8 may or may not be set.

So this is legal: value2 | value7 | value8 This is not legal: value1 | value3 | value7

I need to figure out whether value 7 is set, value8 is set, and what the remaining value is.

I have the following python code. Is there a more elegant way to do this?

value1 = 0x01
value2 = 0x02
value3 = 0x03
value4 = 0x04
value5 = 0x05
value6 = 0x06
value7 = 0x40
value8 = 0x80

def format_byte_as_bits(value):
    return format(value,'b').zfill(8)

def mask_bits_on_byte(byte,mask):
    inverse_of_mask = mask ^ 0b11111111
    return byte & inverse_of_mask

def parse_byte(byte):

    value7_set = byte & value7 == value7
    value8_set = byte & value8 == value8
    byte = mask_bits_on_byte(byte,value7)
    byte = mask_bits_on_byte(byte,value8)
    base_value = byte
    return value7_set,value8_set,base_value

# Example 1
byte = value3 | value7
value7_set,value8_set,base_value = parse_byte(byte)
print("base_value = "+str(base_value))
print("value7_set = "+str(value7_set))
print("value8_set = "+str(value8_set))
print()

# Output:
# base_value = 3
# value7_set = True
# value8_set = False

# Example 2
byte = value5
value7_set,value8_set,base_value = parse_byte(byte)
print("base_value = "+str(base_value))
print("value7_set = "+str(value7_set))
print("value8_set = "+str(value8_set))
print()

# Output:
# base_value = 5
# value7_set = False
# value8_set = False

# Example 3
byte = value1 | value7 | value8
value7_set,value8_set,base_value = parse_byte(byte)
print("base_value = "+str(base_value))
print("value7_set = "+str(value7_set))
print("value8_set = "+str(value8_set))

# Output:
# base_value = 1
# value7_set = True
# value8_set = True

EDIT - I LOVE stackoverflow. So many useful answers, so quickly! You guys are awesome! Wish I could mark all the answers. But I'll at least give everyone an up vote!

EDIT2 - Based on the answers below, the code is simplified to the following:

value1 = 0x01
value2 = 0x02
value3 = 0x03
value4 = 0x04
value5 = 0x05
value6 = 0x06
value7 = 0x40
value8 = 0x80

def parse_byte(byte):
    return byte & value7, byte & 0x80, byte & 7

# Example 1
byte = value3 | value7
value7_set,value8_set,base_value = parse_byte(byte)
print("base_value = "+str(base_value))
if value7_set: print("value7_set")
if value8_set: print("value8_set")
print()

# Example 2
byte = value5
value7_set,value8_set,base_value = parse_byte(byte)
print("base_value = "+str(base_value))
if value7_set: print("value7_set")
if value8_set: print("value8_set")
print()

# Example 3
byte = value1 | value7 | value8
value7_set,value8_set,base_value = parse_byte(byte)
print("base_value = "+str(base_value))
if value7_set: print("value7_set")
if value8_set: print("value8_set")
print()

5 Answers 5

21

Most of your value* constants aren't actually bit masks, only value7 and value8 are. I'd define another bit mask to extract the lower bits, so I would have three bit masks in total:

mask0 = 0x07
mask1 = 0x40
mask2 = 0x80

Now your function becomes

def parse_byte(byte):
    return byte & mask2, byte & mask1, byte & mask0

I did not convert the results to bool -- I don't see why this should be necessary. When checking the returned value with if, it will be implicitly converted to bool anyway.

Also note that

format(value,'b').zfill(8)

can be simplified to

format(value,'08b')
Sign up to request clarification or add additional context in comments.

2 Comments

Very succinct and I appreciate the tip on the zfill as well. I use format(value,'b').zfill(8) all over the place, now I can just use format(value,'08b'). Thanks for your response!
As an aside, an easy way to make proper bitmasks with nice readable code is to write them like value1 = 1 << 0, value2 = 1 << 1 (etc). That is, take a single bit and just change the shift. Errors are more obvious than with hex or decimal literals. If the mask needs multiple bits set, just | those together (eg, value3 = (1 << 2) | (1 << 3) instead of value3 = 0x0c).
12

Given a value such as:

>>> x = 0b10001000

You can find out whether the top bits are set with:

>>> bit8 = bool(x & 0b10000000)
>>> bit7 = bool(x & 0b01000000)

To find which lower bit is set, use a dictionary:

>>> bdict = dict((1<<i, i+1) for i in range(6))
>>> bdict[x & 0b00111111]
4

Comments

4

You don't need the other two functions:

def parse_byte(byte):
    value7_set = byte & value7 == value7
    value8_set = byte & value8 == value8
    base_value =  byte & 7
    return value7_set,value8_set,base_value

1 Comment

Thanks! Didn't think of the byte & 7.
3

It's a little verbose but perfectly fine. The only change I'd make is to simplify parse_byte:

def parse_byte(byte):

     value7_set = byte & value7 == value7
     value8_set = byte & value8 == value8
     base_value = mask_bits_on_byte(byte,value7 | value8)
     return value7_set,value8_set,base_value  

Comments

-1

Wlio to run the byte in the register and use the instruction to get a result will also verify data and cc

1 Comment

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.