333 lines
8.4 KiB
Markdown
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`.
|