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 RATE_HZ = 6.25 # --- 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)