171 lines
6.0 KiB
Python
171 lines
6.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Compare A2 message encoding between Python and C++ reference.
|
|
Verifies bit-level compatibility with GrifoScope implementation.
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
|
|
|
|
from pybusmonitor1553.lib1553.messages.msg_a2 import MsgA2
|
|
from pybusmonitor1553.lib1553.constants import (
|
|
RadarMode, DesignationControl, IntBitStatus, StandbyStatus,
|
|
FreezeStatus, RWSSubmode, RangeScale, BarScan, AzimuthScan
|
|
)
|
|
|
|
def print_word_bits(word, word_num):
|
|
"""Print a 16-bit word with bit positions."""
|
|
print(f"\nWord {word_num}: 0x{word:04X} = 0b{word:016b}")
|
|
print("Bit pos (MSB): F E D C B A 9 8 7 6 5 4 3 2 1 0")
|
|
print(" ", end="")
|
|
for i in range(15, -1, -1):
|
|
bit = (word >> i) & 1
|
|
print(f"{bit} ", end="")
|
|
print()
|
|
|
|
|
|
def analyze_a2_message():
|
|
"""Create and analyze an A2 message matching GrifoScope defaults."""
|
|
msg = MsgA2()
|
|
|
|
# Configuration matching GrifoScope startup (from g346_a1a2.cpp lines 680-682)
|
|
# Phase 1: Protection mode
|
|
msg.master_mode = RadarMode.RWS # 0
|
|
msg.designation_ctrl = DesignationControl.NOT_VALID # 7
|
|
msg.int_bit_req = IntBitStatus.NORMAL # 0
|
|
msg.standby_cmd = StandbyStatus.ON # 1 (protection)
|
|
msg.freeze_cmd = FreezeStatus.NORMAL # 0
|
|
msg.pwr_up_stop_reserved = 0
|
|
msg.reserved_w1_b12 = 0
|
|
msg.silence_reserved = 1 # 1 (protection)
|
|
|
|
# Word 2 params
|
|
msg.rws_submode = RWSSubmode.NAM
|
|
msg.range_scale = RangeScale.NM_80
|
|
msg.bar_scan = BarScan.BAR_2
|
|
msg.azimuth_scan = AzimuthScan.DEG_60
|
|
|
|
# Pack the message
|
|
msg.pack()
|
|
|
|
print("="*70)
|
|
print("A2 MESSAGE ANALYSIS - PHASE 1 PROTECTION MODE")
|
|
print("="*70)
|
|
print("\n📋 Configuration (matching GrifoScope g346_a1a2.cpp:680-682):")
|
|
print(f" master_mode = {msg.master_mode.name:20s} ({msg.master_mode.value})")
|
|
print(f" designation_ctrl = {msg.designation_ctrl.name:20s} ({msg.designation_ctrl.value})")
|
|
print(f" int_bit_req = {msg.int_bit_req.name:20s} ({msg.int_bit_req.value})")
|
|
print(f" standby_cmd = {msg.standby_cmd.name:20s} ({msg.standby_cmd.value}) ← PROTECTION")
|
|
print(f" silence_reserved = {msg.silence_reserved:20d} ← PROTECTION")
|
|
|
|
print("\n📊 Binary word breakdown:")
|
|
for i in range(3):
|
|
word = msg._data[i]
|
|
print_word_bits(word, i)
|
|
|
|
if i == 0:
|
|
# Extract fields manually to verify
|
|
master_mode = (word >> 12) & 0xF
|
|
des_ctrl = (word >> 9) & 0x7
|
|
ibit = (word >> 8) & 0x1
|
|
stby = (word >> 7) & 0x1
|
|
freeze = (word >> 6) & 0x1
|
|
pwr_stop = (word >> 5) & 0x1
|
|
res12 = (word >> 4) & 0x1
|
|
silence = (word >> 3) & 0x1
|
|
|
|
print(f" Decoded fields:")
|
|
print(f" Bits 00-03: master_mode = {master_mode} ({RadarMode(master_mode).name})")
|
|
print(f" Bits 04-06: des_ctrl = {des_ctrl} ({DesignationControl(des_ctrl).name})")
|
|
print(f" Bit 07: ibit = {ibit}")
|
|
print(f" Bit 08: stby = {stby} ← Should be 1")
|
|
print(f" Bit 09: freeze = {freeze}")
|
|
print(f" Bit 10: pwr_stop = {pwr_stop}")
|
|
print(f" Bit 11: reserved = {res12}")
|
|
print(f" Bit 12: silence = {silence} ← Should be 1")
|
|
|
|
# Now test PHASE 2: Operational mode
|
|
print("\n" + "="*70)
|
|
print("PHASE 2: OPERATIONAL MODE (after 120ms)")
|
|
print("="*70)
|
|
|
|
msg.standby_cmd = StandbyStatus.OFF
|
|
msg.silence_reserved = 0
|
|
msg.pack()
|
|
|
|
print(f"\n📋 Updated configuration:")
|
|
print(f" standby_cmd = {msg.standby_cmd.name:20s} ({msg.standby_cmd.value}) ← OPERATIONAL")
|
|
print(f" silence_reserved = {msg.silence_reserved:20d} ← OPERATIONAL")
|
|
|
|
print_word_bits(msg._data[0], 0)
|
|
|
|
word = msg._data[0]
|
|
stby = (word >> 7) & 0x1
|
|
silence = (word >> 3) & 0x1
|
|
print(f" Bit 08: stby = {stby} ← Should be 0")
|
|
print(f" Bit 12: silence = {silence} ← Should be 0")
|
|
|
|
# Expected C++ encoding (from g346_a1a2.cpp)
|
|
print("\n" + "="*70)
|
|
print("EXPECTED C++ REFERENCE VALUES")
|
|
print("="*70)
|
|
print("""
|
|
From g346_a1a2.cpp lines 680-682:
|
|
dSilence.setFromUser(1); // Bit 12 (MSB) = 1
|
|
dStby.setFromUser(1); // Bit 08 (MSB) = 1
|
|
|
|
Expected Word 0 (Phase 1):
|
|
master_mode=0 (RWS), des_ctrl=7 (NOT_VALID), ibit=0, stby=1,
|
|
freeze=0, pwr_stop=0, res=0, silence=1
|
|
|
|
Bit pattern (MSB first, 0-indexed):
|
|
Bits 00-03: master_mode = 0000 (0)
|
|
Bits 04-06: des_ctrl = 111 (7)
|
|
Bit 07: ibit = 0
|
|
Bit 08: stby = 1
|
|
Bit 09: freeze = 0
|
|
Bit 10: pwr_stop = 0
|
|
Bit 11: reserved = 0
|
|
Bit 12: silence = 1
|
|
Bits 13-15: spare = 00
|
|
|
|
= 0b 0000 1110 1000 1000 = 0x0E88
|
|
|
|
Expected Word 0 (Phase 2):
|
|
Same but stby=0, silence=0
|
|
= 0b 0000 1110 0000 0000 = 0x0E00
|
|
""")
|
|
|
|
# Verify actual encoding
|
|
expected_phase1 = 0x0E88 # Corrected calculation
|
|
expected_phase2 = 0x0E00
|
|
|
|
# Re-create phase 1
|
|
msg.standby_cmd = StandbyStatus.ON
|
|
msg.silence_reserved = 1
|
|
msg.pack()
|
|
actual_phase1 = msg._data[0]
|
|
|
|
print(f"\n✓ Verification:")
|
|
print(f" Phase 1: Expected=0x{expected_phase1:04X}, Actual=0x{actual_phase1:04X}", end="")
|
|
if actual_phase1 == expected_phase1:
|
|
print(" ✓ MATCH")
|
|
else:
|
|
print(f" ✗ MISMATCH (diff: 0x{actual_phase1 ^ expected_phase1:04X})")
|
|
|
|
msg.standby_cmd = StandbyStatus.OFF
|
|
msg.silence_reserved = 0
|
|
msg.pack()
|
|
actual_phase2 = msg._data[0]
|
|
|
|
print(f" Phase 2: Expected=0x{expected_phase2:04X}, Actual=0x{actual_phase2:04X}", end="")
|
|
if actual_phase2 == expected_phase2:
|
|
print(" ✓ MATCH")
|
|
else:
|
|
print(f" ✗ MISMATCH (diff: 0x{actual_phase2 ^ expected_phase2:04X})")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
analyze_a2_message()
|