SXXXXXXX_PyBusMonitor1553/doc/Message-Field-Inspector.md
2026-01-20 12:31:23 +01:00

333 lines
8.4 KiB
Markdown

# Message Field Inspector - Documentazione
## Panoramica
Sistema per l'ispezione ed export dei metadati dei campi dei messaggi MIL-STD-1553. Estrae automaticamente per ogni campo:
- **Name**: Nome completo del campo (es: `RDROperationalSettings.spare`)
- **Offset**: Indice della word nel messaggio (0-based)
- **OffsetValue**: Bit di partenza nella word (LSB = 0)
- **Width**: Numero di bit occupati dal campo
- **Type**: Tipo del campo (`bitfield`, `uint16`, `structure`, etc.)
- **EnumType**: Nome del tipo enum se applicabile
---
## File Creati
### 1. `message_inspector.py`
Modulo principale con le classi:
- **`FieldMetadata`**: Rappresenta i metadati di un singolo campo
- **`MessageInspector`**: Ispeziona strutture `ctypes` ed estrae metadati
- **`inspect_all_messages()`**: Ispeziona tutti i messaggi del sistema
### 2. `tools/export_message_fields.py`
Script standalone per export completo di tutti i messaggi in formati JSON e XML.
**Uso:**
```bash
python tools/export_message_fields.py
```
**Output generati:**
- `message_fields_export.json`: JSON con tutti i messaggi
- `message_fields_xml/*.xml`: File XML separati per ogni messaggio
---
## Formato Export
### JSON
```json
{
"A2_MsgRdrOperationCommand": [
{
"Name": "RdrModeCommandWord.des_ctrl",
"Offset": 0,
"OffsetValue": 9,
"Width": 3,
"Type": "bitfield",
"EnumType": "DesignationControl"
}
]
}
```
### XML
```xml
<?xml version="1.0" encoding="UTF-8"?>
<Message name="A2_MsgRdrOperationCommand">
<Fields count="24">
<Field>
<Name>RdrModeCommandWord.des_ctrl</Name>
<Offset>0</Offset>
<OffsetValue>9</OffsetValue>
<Width>3</Width>
<Type>bitfield</Type>
<EnumType>DesignationControl</EnumType>
</Field>
</Fields>
</Message>
```
---
## Uso Programmatico
### Esempio 1: Ispezionare un singolo messaggio
```python
from Grifo_E_1553lib.messages import MessageInspector
from Grifo_E_1553lib.messages.msg_rdr_operation_command import MsgRdrOperationCommand
# Ispeziona messaggio A2
fields = MessageInspector.inspect_message(MsgRdrOperationCommand)
# Stampa informazioni
for field in fields:
print(f"{field.name}: Word={field.word_offset}, Bit={field.bit_offset}, Width={field.width}")
```
### Esempio 2: Export JSON di un messaggio
```python
from Grifo_E_1553lib.messages import MessageInspector
from Grifo_E_1553lib.messages.msg_rdr_settings_and_parameters import MsgRdrSettingsAndParameters
# Ispeziona e converti in JSON
fields = MessageInspector.inspect_message(MsgRdrSettingsAndParameters)
json_output = MessageInspector.export_to_json(fields)
# Salva su file
with open('a1_fields.json', 'w') as f:
f.write(json_output)
```
### Esempio 3: Ispezionare tutti i messaggi
```python
from Grifo_E_1553lib.messages import inspect_all_messages
# Ottieni dizionario di tutti i messaggi
all_messages = inspect_all_messages()
# Itera sui messaggi
for msg_name, fields in all_messages.items():
print(f"\n{msg_name}: {len(fields)} campi")
for field in fields:
if field.width == 1: # Solo flag (1 bit)
print(f" - {field.name}")
```
### Esempio 4: Filtrare campi per criterio
```python
from Grifo_E_1553lib.messages import MessageInspector
from Grifo_E_1553lib.messages.msg_rdr_operation_command import MsgRdrOperationCommand
fields = MessageInspector.inspect_message(MsgRdrOperationCommand)
# Trova tutti i campi enum
enum_fields = [f for f in fields if f.enum_type]
print(f"Campi con enum: {len(enum_fields)}")
# Trova campi nella word 0
word0_fields = [f for f in fields if f.word_offset == 0]
print(f"Campi in word 0: {len(word0_fields)}")
# Trova campi multi-bit (non flag)
multibit_fields = [f for f in fields if f.width > 1]
print(f"Campi multi-bit: {len(multibit_fields)}")
```
---
## Statistiche Export Corrente
**Messaggi ispezionati**: 11
- A1_MsgRdrSettingsAndParameters (38 campi)
- A2_MsgRdrOperationCommand (24 campi)
- A3_MsgGraphicSetting (92 campi)
- A4_MsgNavDataAndCursor (54 campi)
- A5_MsgInuHighSpeed (24 campi)
- A7_Msg1DataLinkTarget (22 campi)
- A8_Msg2DataLinkTarget (21 campi)
- B4_TrackedTarget02_10 (50 campi)
- B5_TrackedTarget01 (80 campi)
- B6_MsgRdrSettingsAndParametersTellback (82 campi)
- B7_MsgRdrStatusTellback (27 campi)
**Totale campi**: 502
---
## Note Tecniche
### Convenzioni Bit Numbering
Il sistema usa la convenzione **Little Endian** di `ctypes`:
- **LSB = bit 0** (bit meno significativo)
- **MSB = bit 15** (bit più significativo)
- I bitfield in `ctypes.LittleEndianStructure` sono numerati sequenzialmente dall'inizio
**Esempio:**
```python
_fields_ = [
("field_a", c_uint16, 2), # bit 0-1
("field_b", c_uint16, 3), # bit 2-4
("field_c", c_uint16, 11), # bit 5-15
]
```
### Word Offset
L'offset delle word è **0-based**:
- Word 0 = prima word del messaggio
- Word 1 = seconda word
- etc.
Le strutture nested incrementano automaticamente il word offset.
### Limitazioni Attuali
- **Solo ctypes.Structure**: supporta solo messaggi basati su `ctypes.Structure/Union`
- **Bitfield semplici**: non gestisce bitfield complessi con maschere custom
- **Enum mapping**: richiede registrazione in `enum_map.ENUM_MAP`
---
## Integrazione Futura
### GUI Integration
Il `MessageInspector` può essere integrato nella GUI per:
- Visualizzazione dettagli campo al click
- Tooltip con metadati campo
- Esportazione dinamica messaggi
### Versioning ICD
Con la struttura v1/v2 in preparazione, l'inspector potrà:
- Comparare campi tra versioni
- Identificare differenze automaticamente
- Validare compatibilità binaria
### Testing
Può essere usato per:
- Generare test di pack/unpack automatici
- Verificare dimensioni messaggi
- Validare mapping ICD vs implementazione
---
## API Reference
### `FieldMetadata`
```python
class FieldMetadata:
name: str # Nome completo campo
word_offset: int # Indice word (0-based)
bit_offset: int # Bit di partenza (LSB=0)
width: int # Numero bit
field_type: str # Tipo campo
enum_type: str # Nome enum (optional)
def to_dict() -> Dict[str, Any]
```
### `MessageInspector`
```python
class MessageInspector:
@staticmethod
def inspect_message(message_class) -> List[FieldMetadata]
@staticmethod
def inspect_structure(structure_class, word_offset=0) -> List[FieldMetadata]
@staticmethod
def export_to_dict(fields) -> List[Dict[str, Any]]
@staticmethod
def export_to_json(fields, indent=2) -> str
@staticmethod
def export_to_xml(fields) -> str
```
### `inspect_all_messages()`
```python
def inspect_all_messages() -> Dict[str, List[FieldMetadata]]
```
Ritorna dizionario con chiave=nome_messaggio, valore=lista_campi.
---
## Esempi Avanzati
### Export CSV Personalizzato
```python
import csv
from Grifo_E_1553lib.messages import inspect_all_messages
all_messages = inspect_all_messages()
with open('fields_export.csv', 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(['Message', 'Field', 'Word', 'Bit', 'Width', 'Type'])
for msg_name, fields in all_messages.items():
for field in fields:
writer.writerow([
msg_name,
field.name,
field.word_offset,
field.bit_offset,
field.width,
field.field_type
])
```
### Comparazione tra Messaggi
```python
from Grifo_E_1553lib.messages import MessageInspector
from Grifo_E_1553lib.messages.msg_rdr_settings_and_parameters import MsgRdrSettingsAndParameters
from Grifo_E_1553lib.messages.msg_rdr_settings_and_parameters_tellback import MsgRdrSettingsAndParametersTellback
# Confronta A1 e B6 (dovrebbero essere simili)
a1_fields = MessageInspector.inspect_message(MsgRdrSettingsAndParameters)
b6_fields = MessageInspector.inspect_message(MsgRdrSettingsAndParametersTellback)
print(f"A1: {len(a1_fields)} campi")
print(f"B6: {len(b6_fields)} campi")
# Trova differenze
a1_names = {f.name for f in a1_fields}
b6_names = {f.name for f in b6_fields}
print(f"\nCampi solo in A1: {a1_names - b6_names}")
print(f"Campi solo in B6: {b6_names - a1_names}")
```
---
## Troubleshooting
**Q: I bitfield hanno offset errati?**
A: Verifica che la struttura usi `ctypes.LittleEndianStructure` e non `ctypes.BigEndianStructure`.
**Q: Enum non vengono rilevati?**
A: Controlla che siano registrati in `Grifo_E_1553lib.data_types.enum_map.ENUM_MAP`.
**Q: Strutture nested non vengono ispezionate?**
A: Verifica che ereditino da `ctypes.Structure` o `ctypes.Union`.