from ..message_base import MessageBase from ..constants import ( Subaddress, CursorMode, CursorSnowplough, CursorGhost, DTTEnable, SAREnable ) from ..fields import BitField, EnumField, ScaledField class MsgA4(MessageBase): """ Message A4: Navigation Data and Acquisition Cursor Data ID: A4 Direction: BC -> RT (Receive) Subaddress: 04 Rate: 50 Hz Document Ref: 7.1.4 """ SUBADDRESS = Subaddress.RX_NAV_DATA IS_TRANSMIT = False RATE_HZ = 50 # --- Word 01: Validity and Slew Data (Ref 7.1.4.1) --- nav_data_invalid = BitField(word_index=0, start_bit=0, width=1) attitude_data_invalid = BitField(word_index=0, start_bit=1, width=1) baro_inertial_alt_invalid = BitField(word_index=0, start_bit=2, width=1) corr_baro_alt_invalid = BitField(word_index=0, start_bit=3, width=1) radalt_invalid = BitField(word_index=0, start_bit=4, width=1) spoi_alt_invalid = BitField(word_index=0, start_bit=5, width=1) spoi_pos_invalid = BitField(word_index=0, start_bit=6, width=1) tas_invalid = BitField(word_index=0, start_bit=7, width=1) cas_invalid = BitField(word_index=0, start_bit=8, width=1) ppos_invalid = BitField(word_index=0, start_bit=9, width=1) antenna_slew_active = BitField(word_index=0, start_bit=10, width=1) cursor_rates_invalid = BitField(word_index=0, start_bit=11, width=1) cursor_mode = EnumField(word_index=0, start_bit=12, width=1, enum_cls=CursorMode) cursor_zero_cmd = BitField(word_index=0, start_bit=13, width=1) cursor_snowplough = EnumField(word_index=0, start_bit=14, width=1, enum_cls=CursorSnowplough) # Bit 15 Spare # --- Word 02: Time Tag (Ref 7.1.4.2) --- # LSB = 64 us time_tag = ScaledField(word_index=1, start_bit=0, width=16, lsb_value=64.0) # --- Word 03: Present True Heading (Ref 7.1.4.3) --- # Semicircles, 2's comp. Range +/- 1.0 (180 deg) true_heading = ScaledField(word_index=2, start_bit=0, width=16, lsb_value=3.05176e-5, signed=True) # --- Word 04: Present Magnetic Heading (Ref 7.1.4.4) --- mag_heading = ScaledField(word_index=3, start_bit=0, width=16, lsb_value=3.05176e-5, signed=True) # --- Word 05-07: Accelerations (Ref 7.1.4.5 - 7.1.4.7) --- # LSB = 0.03125 ft/s^2, 2's comp accel_x = ScaledField(word_index=4, start_bit=0, width=16, lsb_value=0.03125, signed=True) accel_y = ScaledField(word_index=5, start_bit=0, width=16, lsb_value=0.03125, signed=True) accel_z = ScaledField(word_index=6, start_bit=0, width=16, lsb_value=0.03125, signed=True) # --- Word 08: True Air Speed (Ref 7.1.4.8) --- # LSB = 0.125 knots, 2's comp tas = ScaledField(word_index=7, start_bit=0, width=16, lsb_value=0.125, signed=True) # --- Word 09: Calibrated Air Speed (Ref 7.1.4.9) --- # LSB = 1.0 knots, Unsigned cas = ScaledField(word_index=8, start_bit=0, width=16, lsb_value=1.0) # --- Word 10: Barometric/Inertial Altitude (Ref 7.1.4.10) --- # LSB = 4.0 ft, 2's comp baro_inertial_alt = ScaledField(word_index=9, start_bit=0, width=16, lsb_value=4.0, signed=True) # --- Word 11: Corrected Barometric Altitude (Ref 7.1.4.11) --- # LSB = 4.0 ft, 2's comp corr_baro_alt = ScaledField(word_index=10, start_bit=0, width=16, lsb_value=4.0, signed=True) # --- Word 12: Radio Altimeter Altitude (Ref 7.1.4.12) --- # LSB = 2.0 ft, Unsigned radio_alt = ScaledField(word_index=11, start_bit=0, width=16, lsb_value=2.0) # --- Word 13: SPOI Altitude (Ref 7.1.4.13) --- # LSB = 1.0 ft, 2's comp spoi_alt = ScaledField(word_index=12, start_bit=0, width=16, lsb_value=1.0, signed=True) # --- Word 14: Clearance Plane Distance (Ref 7.1.4.14) --- # LSB = 1.0 ft, Unsigned clearance_plane = ScaledField(word_index=13, start_bit=0, width=16, lsb_value=1.0) # --- Word 15: Wind Direction (Ref 7.1.4.15) --- # Semicircles, 2's comp wind_dir = ScaledField(word_index=14, start_bit=0, width=16, lsb_value=3.05176e-5, signed=True) # --- Word 16: Wind Speed (Ref 7.1.4.16) --- # LSB = 0.0625 knots, Unsigned wind_speed = ScaledField(word_index=15, start_bit=0, width=16, lsb_value=0.0625) # --- Word 17-18: Antenna Demands (Ref 7.1.4.17 - 7.1.4.18) --- # Semicircles, 2's comp az_demand = ScaledField(word_index=16, start_bit=0, width=16, lsb_value=3.05176e-5, signed=True) el_demand = ScaledField(word_index=17, start_bit=0, width=16, lsb_value=3.05176e-5, signed=True) # --- Word 19: Cursor Rate X (Ref 7.1.4.19) --- cursor_rate_x = ScaledField(word_index=18, start_bit=0, width=9, lsb_value=1.0, signed=True) # Pixels/sec cursor_ghost = EnumField(word_index=18, start_bit=9, width=1, enum_cls=CursorGhost) dtt_enable = EnumField(word_index=18, start_bit=10, width=1, enum_cls=DTTEnable) sar_enable = EnumField(word_index=18, start_bit=11, width=1, enum_cls=SAREnable) # Bits 12-15 Spare # --- Word 20: Cursor Rate Y (Ref 7.1.4.20) --- cursor_rate_y = ScaledField(word_index=19, start_bit=0, width=9, lsb_value=1.0, signed=True) # Pixels/sec # Bits 9-15 Spare # --- Word 21: Cursor Range (Ref 7.1.4.21) --- # LSB = 8.0 ft, Unsigned cursor_range = ScaledField(word_index=20, start_bit=0, width=16, lsb_value=8.0) # --- Word 22: Cursor Azimuth (Ref 7.1.4.22) --- # Semicircles, 2's comp cursor_azimuth = ScaledField(word_index=21, start_bit=0, width=16, lsb_value=3.05176e-5, signed=True) # --- Word 23: Present Position Data Time Tag (Ref 7.1.4.23) --- ppos_time_tag = ScaledField(word_index=22, start_bit=0, width=16, lsb_value=64.0) # --- Helper for 25-bit Coordinates --- 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 (approx). """ msw = self._data[word_idx_msw] lsw = (self._data[word_idx_lsw] >> 7) & 0x1FF raw_25 = (msw << 9) | lsw if raw_25 & (1 << 24): raw_25 -= (1 << 25) return float(raw_25 * 5.9604644775e-8) # --- Word 24-25: Present Position Latitude (Ref 7.1.4.24) --- @property def ppos_lat(self): return self._get_25bit_semicircle(23, 24) # --- Word 26-27: Present Position Longitude (Ref 7.1.4.25) --- @property def ppos_lon(self): return self._get_25bit_semicircle(25, 26) # --- Word 28-29: SPOI Latitude (Ref 7.1.4.26) --- @property def spoi_lat(self): return self._get_25bit_semicircle(27, 28) # --- Word 30-31: SPOI Longitude (Ref 7.1.4.27) --- @property def spoi_lon(self): return self._get_25bit_semicircle(29, 30)