SXXXXXXX_PyBusMonitor1553/pybusmonitor1553/lib1553/messages/msg_a3.py
2025-12-09 15:52:18 +01:00

167 lines
6.9 KiB
Python

from ..message_base import MessageBase
from ..constants import (
Subaddress, BullsEyeSelect, WaypointType, WaypointQualifier,
InterceptMode, LineStyle, SymbolState, Identity
)
from ..fields import BitField, EnumField, ScaledField, ASCIIField
class MsgA3(MessageBase):
"""
Message A3: Graphic Settings
ID: A3
Direction: BC -> RT (Receive)
Subaddress: 03
Rate: 6.25 Hz
Document Ref: 7.1.3
"""
SUBADDRESS = Subaddress.RX_GRAPHIC
IS_TRANSMIT = False
# --- Word 01: Graphic Order (Ref 7.1.3.1) ---
# Graphic Symbols Enable Flags (1=Display)
show_waypoint_1 = BitField(word_index=0, start_bit=0, width=1)
show_waypoint_2 = BitField(word_index=0, start_bit=1, width=1)
show_waypoint_3 = BitField(word_index=0, start_bit=2, width=1)
show_intercept_fd = BitField(word_index=0, start_bit=3, width=1)
show_break_away_cue = BitField(word_index=0, start_bit=4, width=1)
show_intercept_zones = BitField(word_index=0, start_bit=5, width=1)
show_ttg_cursor = BitField(word_index=0, start_bit=6, width=1)
show_asec_circle = BitField(word_index=0, start_bit=7, width=1)
show_attack_steering = BitField(word_index=0, start_bit=8, width=1)
# Bull's Eye Selection
bullseye_select = EnumField(word_index=0, start_bit=9, width=2, enum_cls=BullsEyeSelect)
# Bits 11-15 Spare
# --- Word 02: Time-to-Go to Cursor (Ref 7.1.3.2) ---
# LSB = 1 sec
ttg_cursor = ScaledField(word_index=1, start_bit=0, width=16, lsb_value=1.0)
# --- Helper function for 25-bit Semicircles (Lat/Lon) ---
def _get_25bit_semicircle(self, word_idx_msw, word_idx_lsw):
"""
Combines MSW (16 bit) and LSW (9 bit) to form a 25-bit 2's complement
Semicircle value. LSB = 5.96046e-8.
"""
msw = self._data[word_idx_msw]
# LSW uses only bits 0-8 (9 bits)
lsw = (self._data[word_idx_lsw] >> 7) & 0x1FF
# Combine: MSW is top 16 bits, LSW is bottom 9 bits
raw_25 = (msw << 9) | lsw
# Handle 2's complement for 25 bits
if raw_25 & (1 << 24): # Sign bit check
raw_25 -= (1 << 25)
# Scale (1.0 full scale / 2^24) approx 5.96046e-8
return float(raw_25 * 5.9604644775e-8)
# --- Waypoint 1 Data (Ref 7.1.3.3 - 7.1.3.4) ---
# Raw accessors for internal use if needed, but properties are preferred
_wp1_lat_msw = BitField(word_index=2, start_bit=0, width=16)
_wp1_lat_lsw = BitField(word_index=3, start_bit=0, width=9) # Bits 0-8
@property
def wp1_latitude(self):
return self._get_25bit_semicircle(2, 3)
wp1_type = EnumField(word_index=3, start_bit=9, width=1, enum_cls=WaypointType)
wp1_qualifier_valid = BitField(word_index=3, start_bit=10, width=1)
wp1_qualifier_val = EnumField(word_index=3, start_bit=11, width=2, enum_cls=WaypointQualifier)
# WP1 Longitude
@property
def wp1_longitude(self):
return self._get_25bit_semicircle(4, 5)
wp1_code = BitField(word_index=5, start_bit=9, width=7) # 0-99
# --- Waypoint 2 Data (Ref 7.1.3.5 - 7.1.3.6) ---
@property
def wp2_latitude(self):
return self._get_25bit_semicircle(6, 7)
wp2_type = EnumField(word_index=7, start_bit=9, width=1, enum_cls=WaypointType)
wp2_qualifier_valid = BitField(word_index=7, start_bit=10, width=1)
wp2_qualifier_val = EnumField(word_index=7, start_bit=11, width=2, enum_cls=WaypointQualifier)
@property
def wp2_longitude(self):
return self._get_25bit_semicircle(8, 9)
wp2_code = BitField(word_index=9, start_bit=9, width=7)
# --- Waypoint 3 Data (Ref 7.1.3.7 - 7.1.3.8) ---
@property
def wp3_latitude(self):
return self._get_25bit_semicircle(10, 11)
wp3_type = EnumField(word_index=11, start_bit=9, width=1, enum_cls=WaypointType)
wp3_qualifier_valid = BitField(word_index=11, start_bit=10, width=1)
wp3_qualifier_val = EnumField(word_index=11, start_bit=11, width=2, enum_cls=WaypointQualifier)
@property
def wp3_longitude(self):
return self._get_25bit_semicircle(12, 13)
wp3_code = BitField(word_index=13, start_bit=9, width=7)
# --- Intercept Flight Director (Ref 7.1.3.9 - 7.1.3.10) ---
ifd_x = BitField(word_index=14, start_bit=0, width=9) # Pixels
ifd_mode = EnumField(word_index=14, start_bit=10, width=1, enum_cls=InterceptMode)
ifd_style = EnumField(word_index=14, start_bit=11, width=1, enum_cls=LineStyle)
ifd_y = BitField(word_index=15, start_bit=0, width=9) # Pixels
# --- Intercept Zones (Ref 7.1.3.11 - 7.1.3.14) ---
int_zone_rmin_y = BitField(word_index=16, start_bit=0, width=9)
int_zone_rmax_y = BitField(word_index=17, start_bit=0, width=9)
no_escape_rmax_y = BitField(word_index=18, start_bit=0, width=9)
int_zone_target_tip_y = BitField(word_index=19, start_bit=0, width=9)
# --- ASEC (Ref 7.1.3.15) ---
asec_radius = BitField(word_index=20, start_bit=0, width=9)
asec_blink = EnumField(word_index=20, start_bit=9, width=1, enum_cls=SymbolState)
# --- Attack Steering Cue (Ref 7.1.3.16 - 7.1.3.17) ---
asc_x = BitField(word_index=21, start_bit=0, width=9)
asc_blink = EnumField(word_index=21, start_bit=10, width=1, enum_cls=SymbolState)
asc_y = BitField(word_index=22, start_bit=0, width=9)
# --- Tracked Target Info (Ref 7.1.3.18) ---
hpt_in_int_zone = BitField(word_index=23, start_bit=0, width=1)
hpt_datalink_corr = BitField(word_index=23, start_bit=1, width=1)
hpt_identity = EnumField(word_index=23, start_bit=2, width=1, enum_cls=Identity)
spt_in_int_zone = BitField(word_index=23, start_bit=3, width=1)
spt_datalink_corr = BitField(word_index=23, start_bit=4, width=1)
spt_identity = EnumField(word_index=23, start_bit=5, width=1, enum_cls=Identity)
# TWS Targets in Zone (Bits 6-13)
tws_tgt_1_in_zone = BitField(word_index=23, start_bit=6, width=1)
tws_tgt_2_in_zone = BitField(word_index=23, start_bit=7, width=1)
# ... bits 8-13 follow same logic for targets 3-8
# --- Call Signs (Ref 7.1.3.19 - 7.1.3.20) ---
hpt_callsign_ab = ASCIIField(word_index=24) # Chars 1 & 2
hpt_callsign_cd = ASCIIField(word_index=25) # Chars 3 & 4
spt_callsign_ab = ASCIIField(word_index=26)
spt_callsign_cd = ASCIIField(word_index=27)
# --- Track IDs (Ref 7.1.3.21 - 7.1.3.24) ---
# These are 8-bit IDs. We use BitField manually.
tws_id_01 = BitField(word_index=28, start_bit=0, width=8)
tws_id_02 = BitField(word_index=28, start_bit=8, width=8)
tws_id_03 = BitField(word_index=29, start_bit=0, width=8)
tws_id_04 = BitField(word_index=29, start_bit=8, width=8)
tws_id_05 = BitField(word_index=30, start_bit=0, width=8)
tws_id_06 = BitField(word_index=30, start_bit=8, width=8)
tws_id_07 = BitField(word_index=31, start_bit=0, width=8)
tws_id_08 = BitField(word_index=31, start_bit=8, width=8)