Refer to a memory location as a volatile structure variable. Args: mem : memory manager instance address : bind address Example: >>> class Point(BaseStruct): ... _fields_ = [ ... ('x', ctypes.c_uint32),
(cls, mem: QlMemoryManager, address: int)
| 57 | |
| 58 | @classmethod |
| 59 | def volatile_ref(cls, mem: QlMemoryManager, address: int): |
| 60 | """Refer to a memory location as a volatile structure variable. |
| 61 | |
| 62 | Args: |
| 63 | mem : memory manager instance |
| 64 | address : bind address |
| 65 | |
| 66 | Example: |
| 67 | >>> class Point(BaseStruct): |
| 68 | ... _fields_ = [ |
| 69 | ... ('x', ctypes.c_uint32), |
| 70 | ... ('y', ctypes.c_uint32) |
| 71 | ... ] |
| 72 | |
| 73 | >>> # bind a volatile Point structure to address `ptr` |
| 74 | >>> p = Point.volatile_ref(ql.mem, ptr) |
| 75 | ... if p.x > 10: # x value is read directly from memory |
| 76 | ... p.x = 10 # x value is written directly to memory |
| 77 | ... # y value in memory remains unchanged |
| 78 | >>> |
| 79 | """ |
| 80 | |
| 81 | # map all structure field names to their types |
| 82 | _fields = dict((fname, ftype) for fname, ftype, *_ in cls._fields_) |
| 83 | |
| 84 | class VolatileStructRef(cls): |
| 85 | """Turn a BaseStruct subclass into a volatile structure. |
| 86 | |
| 87 | Field values are never cached: when retrieving a field's value, its value |
| 88 | is read from memory and when setting a field's value, its value is flushed |
| 89 | to memory. |
| 90 | |
| 91 | This is useful to make sure a structure's fields are alway synced with memory. |
| 92 | """ |
| 93 | |
| 94 | def __getattribute__(self, name: str) -> Any: |
| 95 | # accessing a structure field? |
| 96 | if name in _fields: |
| 97 | field = cls.__dict__[name] |
| 98 | ftype = _fields[name] |
| 99 | |
| 100 | if issubclass(ftype, BaseStruct): |
| 101 | fvalue = ftype.volatile_ref(mem, address + field.offset) |
| 102 | |
| 103 | else: |
| 104 | # load field's bytes from memory and tranform them into a value |
| 105 | data = mem.read(address + field.offset, field.size) |
| 106 | fvalue = ftype.from_buffer(data) |
| 107 | |
| 108 | if hasattr(fvalue, 'value'): |
| 109 | fvalue = fvalue.value |
| 110 | |
| 111 | # set the value to the structure in order to maintain consistency with ctypes.Structure |
| 112 | super().__setattr__(name, fvalue) |
| 113 | return fvalue |
| 114 | |
| 115 | # return attribute value |
| 116 | return super().__getattribute__(name) |