Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python ctype-bitfields: get bitfield location

I have created a ctype bitfield structure with a corresponding Union to access it both by single bitfield and by integer value. I was able to set the single field using a variable that contains the name of the field, but now I'd like to know to which byte the specific field belongs to. Here is an example of my code:

import ctypes

c_short = ctypes.c_uint16

class Flags_bits(ctypes.LittleEndianStructure):
    _fields_ = [
        ("bitField1", c_short, 1),
        ("bitField2", c_short, 4),
        ("bitField3", c_short, 6),
        ("bitField4", c_short, 1),
        ("bitField5", c_short, 2),
        ("bitField6", c_short, 2),

        ("bitField7", c_short, 6),
        ("bitField8", c_short, 4),
        ("bitField9", c_short, 4),
        ("bitField10", c_short, 1),
        ("bitField11", c_short, 1)]

class Flags(ctypes.Union):
    _fields_ = [("b", Flags_bits),
                ("asInt", c_short*6)]

def setFlag (flagName, value):
    flags = Flags()
    setattr(flags.b, flagName, value)        
    print getattr(flags.b, flagName)

Now what I want to know is to which integer my flag belongs to (i.e. to which flags.asInt[i]), I was looking for a sort of "get_location" attribute to get the flag location in the structure and from this retrieve the 'i' index of the integer, but I couldn't find anything Is there a simple way to do that?

Thanks in advance for every reply!

like image 905
toti08 Avatar asked Feb 13 '23 04:02

toti08


1 Answers

Each field descriptor in a Structure has an offset attribute that defines the byte offset of its storage unit. It also has a size attribute whose meaning depends on whether or not it's a bit field. If it's a bit field, the low word of size contains the field's storage-unit bit offset, and the high word contains the number of bits in the field. Otherwise size is the field's size in bytes.

Since your bit-field storage units are all c_short, you can simply divide a field's byte offset by sizeof(c_short) to calculate the corresponding item in asInt. For example, Flags_bits.bitField6.offset // 2 == 0 and Flags_bits.bitField7.offset // 2 == 1.

You can also compute the range of bits for each field:

import ctypes

c_short = ctypes.c_cshort

class Flags_bits(ctypes.LittleEndianStructure):
    _fields_ = [("bitField1", c_short, 1),
                ("bitField2", c_short, 4),
                ("bitField3", c_short, 6),
                ("bitField4", c_short, 1),
                ("bitField5", c_short, 2),
                ("bitField6", c_short, 2),
                ("bitField7", c_short, 6),
                ("bitField8", c_short, 4),
                ("bitField9", c_short, 4),
                ("bitField10", c_short, 1),
                ("bitField11", c_short, 1)]


for field_descr in Flags_bits._fields_:        
    name = field_descr[0]
    field = getattr(Flags_bits, name)    
    bfield_bits = field.size >> 16    
    if bfield_bits:
        start = 8 * field.offset + field.size & 0xFFFF
        stop = start + bfield_bits
    else:
        start = 8 * field.offset
        stop = start + 8 * field.size
    print("{:>10s}: bits {:>2d}:{:>2d}".format(
          name, start, stop))

Output:

 bitField1: bits  0: 1
 bitField2: bits  1: 5
 bitField3: bits  5:11
 bitField4: bits 11:12
 bitField5: bits 12:14
 bitField6: bits 14:16
 bitField7: bits 16:22
 bitField8: bits 22:26
 bitField9: bits 26:30
bitField10: bits 30:31
bitField11: bits 31:32
like image 194
Eryk Sun Avatar answered Feb 24 '23 03:02

Eryk Sun