import ctypes from enum import Enum def inspect_structure(obj): """ Analizza ricorsivamente una struttura o unione ctypes e ritorna un dizionario che descrive la gerarchia dei dati, i valori attuali e i metadati per la GUI. """ # 1. Gestione Smart Types (es. Velocity, Semicircle) # Se la classe ha una property 'value' o 'degrees', la trattiamo come un valore singolo cls = obj.__class__ if hasattr(cls, 'value') and isinstance(getattr(cls, 'value'), property): return { "type": "smart_value", "value": obj.value, "obj_ref": obj, # Riferimento all'oggetto per il setter "attr_name": "value" # Nome dell'attributo da settare } if hasattr(cls, 'degrees') and isinstance(getattr(cls, 'degrees'), property): return { "type": "smart_angle", "value": obj.degrees, "obj_ref": obj, "attr_name": "degrees" } # 2. Gestione Strutture Complesse (Structure o Union) if hasattr(obj, "_fields_"): children = {} # Recuperiamo eventuali metadati per gli Enum definiti nella classe # Esempio: _enums_ = {"target_history": TargetHistory} enums_map = getattr(obj, "_enums_", {}) for field_desc in obj._fields_: field_name = field_desc[0] field_type = field_desc[1] # Saltiamo i campi 'raw' se esiste una vista 'bits' o 'fields' (tipico delle Union) if field_name == "raw" and (hasattr(obj, "bits") or hasattr(obj, "fields")): continue field_val = getattr(obj, field_name) # Caso A: Campo mappato su Enum if field_name in enums_map: enum_cls = enums_map[field_name] try: current_enum = enum_cls(field_val) except ValueError: # Se il valore raw non รจ nell'enum, gestiamo l'errore o usiamo un fallback current_enum = field_val children[field_name] = { "type": "enum", "value": current_enum, "enum_cls": enum_cls, "obj_ref": obj, "attr_name": field_name } # Caso B: Altra Struttura/Union (Ricorsione) elif hasattr(field_val, "_fields_"): children[field_name] = inspect_structure(field_val) # Caso C: Primitiva (int, float, array fissi) else: # Gestione array ctypes semplici if hasattr(field_type, "_length_"): # Per ora semplifichiamo gli array come stringa o lista non editabile val_repr = str(list(field_val)) children[field_name] = {"type": "readonly", "value": val_repr} else: children[field_name] = { "type": "primitive", "value": field_val, "obj_ref": obj, "attr_name": field_name } return {"type": "compound", "children": children} # Fallback return {"type": "unknown", "value": str(obj)} def structure_to_dict(obj): """ Convert a ctypes.Structure (possibly containing nested structures and enums) into a nested Python dict with primitive values and enum names where possible. """ # Handle smart types first similar to inspect_structure cls = obj.__class__ if hasattr(cls, 'value') and isinstance(getattr(cls, 'value'), property): return obj.value if hasattr(cls, 'degrees') and isinstance(getattr(cls, 'degrees'), property): return obj.degrees if hasattr(obj, '_fields_'): result = {} enums_map = getattr(obj, '_enums_', {}) for field_desc in obj._fields_: field_name = field_desc[0] field_type = field_desc[1] # Skip raw fields exposed by unions if field_name == 'raw' and (hasattr(obj, 'bits') or hasattr(obj, 'fields')): continue try: val = getattr(obj, field_name) except Exception: result[field_name] = None continue if field_name in enums_map: enum_cls = enums_map[field_name] try: result[field_name] = enum_cls(val).name except Exception: result[field_name] = val elif hasattr(val, '_fields_'): result[field_name] = structure_to_dict(val) else: # ctypes arrays -> convert to list if hasattr(field_type, '_length_'): try: result[field_name] = list(val) except Exception: result[field_name] = str(val) else: # Primitive # Convert c_uint8/16/32 etc. to Python int try: if hasattr(val, 'value'): result[field_name] = val.value else: result[field_name] = val except Exception: result[field_name] = val return result # Fallback: return string return str(obj)