/// <summary> /// Decodes a coarse format TIS-B airborne position message. /// </summary> /// <param name="message"></param> private void DecodeCoarseTisbAirbornePosition(AdsbMessage message) { message.MessageFormat = MessageFormat.CoarseTisbAirbornePosition; var subMessage = message.CoarseTisbAirbornePosition = new CoarseTisbAirbornePosition(); message.TisbIcaoModeAFlag = _BitStream.ReadByte(1); subMessage.SurveillanceStatus = (SurveillanceStatus)_BitStream.ReadByte(2); subMessage.ServiceVolumeID = _BitStream.ReadByte(4); var rawAltitude = _BitStream.ReadUInt16(12); var acCode = ((rawAltitude & 0xfe0) >> 1) | (rawAltitude & 0x0f); if ((rawAltitude & 0x10) != 0) { subMessage.BarometricAltitude = ModeSAltitudeConversion.CalculateBinaryAltitude(acCode); } else { subMessage.BarometricAltitude = ModeSAltitudeConversion.LookupGillhamAltitude(acCode); } var groundTrackValid = _BitStream.ReadBit(); var groundTrack = _BitStream.ReadByte(5); var groundSpeed = _BitStream.ReadByte(6); if (groundTrackValid) { subMessage.GroundTrack = (double)groundTrack * 11.25; } subMessage.GroundSpeed = (double)groundSpeed * 16.0; subMessage.CompactPosition = ExtractCprCoordinate(message, 12, ignoreMessageType: true); }
/// <summary> /// Decodes a surface position message. /// </summary> /// <param name="message"></param> private void DecodeSurfacePosition(AdsbMessage message) { message.MessageFormat = MessageFormat.SurfacePosition; var subMessage = message.SurfacePosition = new SurfacePositionMessage(); var movement = _BitStream.ReadByte(7); if (movement > 0) { if (movement < 124) { subMessage.GroundSpeed = _SurfaceGroundSpeed[movement]; } else if (movement == 124) { subMessage.GroundSpeed = 175.0; subMessage.GroundSpeedExceeded = true; } else if (movement == 127) { subMessage.IsReversing = true; } } var trackIsValid = _BitStream.ReadBit(); var track = _BitStream.ReadByte(7); if (trackIsValid) { subMessage.GroundTrack = track * 2.8125; } subMessage.PositionTimeIsExact = _BitStream.ReadBit(); subMessage.CompactPosition = ExtractCprCoordinate(message, 19); }
/// <summary> /// Decodes an identification and emitter category message. /// </summary> /// <param name="message"></param> private void DecodeIdentification(AdsbMessage message) { message.MessageFormat = MessageFormat.IdentificationAndCategory; var subMessage = message.IdentifierAndCategory = new IdentifierAndCategoryMessage(); subMessage.EmitterCategory = _EmitterCategories[message.Type - 1, _BitStream.ReadByte(3)]; subMessage.Identification = ModeSCharacterTranslator.ExtractCharacters(_BitStream, 8); }
public void ModeSMessageEventArgs_Constructor_Initialises_To_Known_State() { var dateTimeNow = DateTime.UtcNow; var message = new ModeSMessage(); var adsbMessage = new AdsbMessage(message); var eventArgs = new ModeSMessageEventArgs(dateTimeNow, message, adsbMessage); Assert.AreEqual(dateTimeNow, eventArgs.ReceivedUtc); Assert.AreSame(message, eventArgs.ModeSMessage); Assert.AreSame(adsbMessage, eventArgs.AdsbMessage); }
/// <summary> /// Extracts the fields describing a Compact Position Reporting coordinate in a message. /// </summary> /// <param name="message"></param> /// <param name="encodingBits"></param> /// <returns></returns> private CompactPositionReportingCoordinate ExtractCprCoordinate(AdsbMessage message, byte encodingBits) { CompactPositionReportingCoordinate result = null; if (message.Type != 0) { bool isOddFormat = _BitStream.ReadBit(); int latitude = (int)_BitStream.ReadUInt32(17); int longitude = (int)_BitStream.ReadUInt32(17); result = new CompactPositionReportingCoordinate(latitude, longitude, isOddFormat, encodingBits); } return(result); }
/// <summary> /// Extracts the fields describing a Compact Position Reporting coordinate in a message. /// </summary> /// <param name="message"></param> /// <param name="encodingBits"></param> /// <param name="ignoreMessageType"></param> /// <returns></returns> private CompactPositionReportingCoordinate ExtractCprCoordinate(AdsbMessage message, byte encodingBits, bool ignoreMessageType = false) { CompactPositionReportingCoordinate result = null; var readBits = encodingBits >= 17 ? 17 : encodingBits; if (message.Type != 0 || ignoreMessageType) { bool isOddFormat = _BitStream.ReadBit(); int latitude = (int)_BitStream.ReadUInt32(readBits); int longitude = (int)_BitStream.ReadUInt32(readBits); result = new CompactPositionReportingCoordinate(latitude, longitude, isOddFormat, encodingBits); } return(result); }
/// <summary> /// Decodes an identification and emitter category message. /// </summary> /// <param name="message"></param> private void DecodeIdentification(AdsbMessage message) { message.MessageFormat = MessageFormat.IdentificationAndCategory; var subMessage = message.IdentifierAndCategory = new IdentifierAndCategoryMessage(); subMessage.EmitterCategory = _EmitterCategories[message.Type - 1, _BitStream.ReadByte(3)]; subMessage.Identification = ModeSCharacterTranslator.ExtractCharacters(_BitStream, 8); if (IsFineFormatTisb(message)) { // These are only sent for TIS-B fine format messages with a valid ICAO24, in which case the // IMF flag can be assumed to be zero message.TisbIcaoModeAFlag = 0; } }
/// <summary> /// Decodes an airborne position message. /// </summary> /// <param name="message"></param> private void DecodeAirbornePosition(AdsbMessage message) { message.MessageFormat = message.Type == 0 ? MessageFormat.NoPositionInformation : MessageFormat.AirbornePosition; var subMessage = message.AirbornePosition = new AirbornePositionMessage(); subMessage.SurveillanceStatus = (SurveillanceStatus)_BitStream.ReadByte(2); if (IsFineFormatTisb(message)) { message.TisbIcaoModeAFlag = _BitStream.ReadByte(1); } else { if (message.Type == 0) { _BitStream.Skip(1); } else { subMessage.NicB = (byte)(_BitStream.ReadBit() ? 2 : 0); } } var rawAltitude = _BitStream.ReadUInt16(12); var acCode = ((rawAltitude & 0xfe0) >> 1) | (rawAltitude & 0x0f); int?altitude = null; if ((rawAltitude & 0x10) != 0) { altitude = ModeSAltitudeConversion.CalculateBinaryAltitude(acCode); } else { altitude = ModeSAltitudeConversion.LookupGillhamAltitude(acCode); } if (message.Type < 20) { subMessage.BarometricAltitude = altitude; } else { subMessage.GeometricAltitude = altitude; } subMessage.PositionTimeIsExact = _BitStream.ReadBit(); subMessage.CompactPosition = ExtractCprCoordinate(message, 17); }
public void AdsbMessage_Constructor_Initialises_To_Known_Values_And_Properties_Work() { var modeSMessage = new ModeSMessage(); var message = new AdsbMessage(modeSMessage); Assert.AreSame(modeSMessage, message.ModeSMessage); TestUtilities.TestProperty(message, m => m.AirbornePosition, null, new AirbornePositionMessage()); TestUtilities.TestProperty(message, m => m.AirborneVelocity, null, new AirborneVelocityMessage()); TestUtilities.TestProperty(message, m => m.IdentifierAndCategory, null, new IdentifierAndCategoryMessage()); TestUtilities.TestProperty(message, m => m.MessageFormat, MessageFormat.None, MessageFormat.AircraftOperationalStatus); TestUtilities.TestProperty(message, m => m.SurfacePosition, null, new SurfacePositionMessage()); TestUtilities.TestProperty(message, m => m.TargetStateAndStatus, null, new TargetStateAndStatusMessage()); TestUtilities.TestProperty(message, m => m.Type, (byte)0, (byte)255); TestUtilities.TestProperty(message, m => m.AircraftStatus, null, new AircraftStatusMessage()); TestUtilities.TestProperty(message, m => m.AircraftOperationalStatus, null, new AircraftOperationalStatusMessage()); }
private void UpdateView(AdsbMessage message) { string key = message.ModeSMessage.FormattedIcao24; if (message.ModeSMessage.Identity.HasValue) { UpdateViewModelField(key, "Squawk", message.ModeSMessage.Identity.Value.ToString("0000")); } switch (message.MessageFormat) { case MessageFormat.IdentificationAndCategory: UpdateViewModelField(key, "Identification", message.IdentifierAndCategory.Identification); UpdateViewModelField(key, "Category", message.IdentifierAndCategory.EmitterCategory.ToString()); break; case MessageFormat.AirborneVelocity: if (message.AirborneVelocity.VectorVelocity != null && message.AirborneVelocity.VectorVelocity.Speed.HasValue) { UpdateViewModelField(key, "AirborneVelocity", Math.Round(message.AirborneVelocity.VectorVelocity.Speed.Value, 0, MidpointRounding.AwayFromZero).ToString()); } break; case MessageFormat.AircraftOperationalStatus: UpdateViewModelField(key, "SIL", message.AircraftOperationalStatus.Sil.ToString()); UpdateViewModelField(key, "SDA", message.AircraftOperationalStatus.SystemDesignAssurance.ToString()); break; case MessageFormat.AirbornePosition: UpdateViewModelField(key, "BarometricAltitude", message.AirbornePosition.BarometricAltitude.ToString()); UpdateViewModelField(key, "Lattitude", message.AirbornePosition.CompactPosition.Latitude.ToString()); UpdateViewModelField(key, "Longitude", message.AirbornePosition.CompactPosition.Longitude.ToString()); break; case MessageFormat.AircraftStatus: if (message.AircraftStatus.EmergencyStatus.Squawk.HasValue) { UpdateViewModelField(key, "Squawk", message.AircraftStatus.EmergencyStatus.Squawk.Value.ToString("0000")); } break; } }
/// <summary> /// Creates a new object. /// </summary> /// <param name="utcNow"></param> /// <param name="modeSMessage"></param> /// <param name="adsbMessage"></param> public ModeSMessageEventArgs(DateTime utcNow, ModeSMessage modeSMessage, AdsbMessage adsbMessage) { ReceivedUtc = utcNow; ModeSMessage = modeSMessage; AdsbMessage = adsbMessage; }
public MainForm() { InitializeComponent(); _dataSet.Columns.Add("ICAO", typeof(string)); _dataSet.Columns.Add("LastUpdate", typeof(DateTime)); _dataSet.Columns.Add("Identification", typeof(string)); _dataSet.Columns.Add("Category", typeof(string)); _dataSet.Columns.Add("Squawk", typeof(string)); _dataSet.Columns.Add("AirborneVelocity", typeof(string)); _dataSet.Columns.Add("SIL", typeof(string)); _dataSet.Columns.Add("SDA", typeof(string)); _dataSet.Columns.Add("BarometricAltitude", typeof(string)); _dataSet.Columns.Add("Lattitude", typeof(string)); _dataSet.Columns.Add("Longitude", typeof(string)); dataGridView1.DataSource = _dataSet; dataGridView1.Columns["LastUpdate"].DefaultCellStyle.Format = "dd/MM/yyyy HH:mm:ss"; dataGridView1.Columns["LastUpdate"].Width = 130; var adsbTranslator = new AdsbTranslator(); adsbTranslator.Statistics = new Statistics(); Text = "ADSB# v" + Assembly.GetExecutingAssembly().GetName().Version; _decoder.FrameReceived += delegate(byte[] frame, int length) { Interlocked.Increment(ref _frameCount); var t = new ModeSTranslator(); t.Statistics = new Statistics(); var modeSMessage = t.Translate(frame, 0, null, false); AdsbTranslator t2 = new AdsbTranslator(); t2.Statistics = new Statistics(); AdsbMessage adsbMessage = t2.Translate(modeSMessage); if (adsbMessage != null) { BeginInvoke(new Action(delegate { Debug.Print(adsbMessage.ToString()); UpdateView(adsbMessage); })); } }; confidenceNumericUpDown_ValueChanged(null, null); timeoutNumericUpDown_ValueChanged(null, null); try { _rtlDevice.Open(); var devices = DeviceDisplay.GetActiveDevices(); deviceComboBox.Items.Clear(); deviceComboBox.Items.AddRange(devices); //_initialized = true; deviceComboBox.SelectedIndex = 0; deviceComboBox_SelectedIndexChanged(null, null); } catch (Exception e) { MessageBox.Show(e.Message); } }
/// <summary> /// See interface docs. /// </summary> /// <param name="modeSMessage"></param> /// <returns></returns> public AdsbMessage Translate(ModeSMessage modeSMessage) { AdsbMessage result = null; if (modeSMessage != null && modeSMessage.ExtendedSquitterMessage != null && modeSMessage.ExtendedSquitterMessage.Length == 7) { _BitStream.Initialise(modeSMessage.ExtendedSquitterMessage); result = new AdsbMessage(modeSMessage); result.Type = _BitStream.ReadByte(5); switch (result.Type) { case 0: DecodeAirbornePosition(result); break; case 1: case 2: case 3: case 4: DecodeIdentification(result); break; case 5: case 6: case 7: case 8: DecodeSurfacePosition(result); break; case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: DecodeAirbornePosition(result); break; case 19: DecodeVelocity(result); break; case 20: case 21: case 22: DecodeAirbornePosition(result); break; case 28: DecodeAircraftStatus(result); break; case 29: DecodeTargetStateAndStatus(result); break; case 31: DecodeAircraftOperationalStatus(result); break; } if (_Statistics.Lock != null) { lock (_Statistics.Lock) { ++_Statistics.AdsbCount; ++_Statistics.AdsbMessageFormatCount[(int)result.MessageFormat]; ++_Statistics.AdsbTypeCount[result.Type]; } } } return(result); }
/// <summary> /// Returns true if the parent Mode-S message indicates that this is the payload from a coarse-format TIS-B message. /// </summary> /// <param name="message"></param> /// <returns></returns> private bool IsCoarseFormatTisb(AdsbMessage message) { return(message.ModeSMessage.DownlinkFormat == DownlinkFormat.ExtendedSquitterNonTransponder && message.ModeSMessage.ControlField == ControlField.CoarseFormatTisb); }
/// <summary> /// Decodes the content of aircraft operational status messages. /// </summary> /// <param name="message"></param> private void DecodeAircraftOperationalStatus(AdsbMessage message) { message.MessageFormat = MessageFormat.AircraftOperationalStatus; var subMessage = message.AircraftOperationalStatus = new AircraftOperationalStatusMessage(); var subType = _BitStream.ReadByte(3); subMessage.AircraftOperationalStatusType = (AircraftOperationalStatusType)subType; bool isSurfaceCapability = subMessage.AircraftOperationalStatusType == AircraftOperationalStatusType.SurfaceCapability; var cc = _BitStream.ReadUInt16(isSurfaceCapability ? 12 : 16); var len = isSurfaceCapability ? _BitStream.ReadByte(4) : (byte)0; var om = _BitStream.ReadUInt16(16); var version = subMessage.AdsbVersion = _BitStream.ReadByte(3); if (version < 3 && subType < 2) { switch (subType) { case 0: subMessage.AirborneCapability = cc; break; case 1: if (version > 0) { subMessage.SurfaceCapability = (SurfaceCapability)cc; if (version != 0 && (version != 2 || len != 0)) { subMessage.MaximumLength = _MaximumLengths[len]; subMessage.MaximumWidth = _MaximumWidths[len]; } } break; } if (version > 0) { subMessage.OperationalMode = (OperationalMode)om; if (version == 2) { subMessage.SystemDesignAssurance = (SystemDesignAssurance)((om & 0x300) >> 8); if (subType == 1) { var gpsRight = (om & 0x80); var gpsLat = (om & 0x60) >> 5; var gpsLon = om & 0x1f; if (gpsRight != 0 || gpsLat != 0) { subMessage.LateralAxisGpsOffset = (short)((gpsRight != 0 ? -1 : 1) * (gpsLat * 2)); } if (gpsLon > 1) { subMessage.LongitudinalAxisGpsOffset = (byte)((gpsLon - 1) * 2); } } } subMessage.NicA = _BitStream.ReadBit() ? (byte)4 : (byte)0; if (version == 2 && subType == 1) { subMessage.NicC = (byte)(om & 0x01); } subMessage.NacP = _BitStream.ReadByte(4); if (version == 2 && subType == 0) { subMessage.Gva = _BitStream.ReadByte(2); } else { _BitStream.Skip(2); } subMessage.Sil = _BitStream.ReadByte(2); if (subType == 0) { subMessage.NicBaro = _BitStream.ReadBit(); } else { subMessage.SurfacePositionAngleIsTrack = _BitStream.ReadBit(); } subMessage.HorizontalReferenceIsMagneticNorth = _BitStream.ReadBit(); if (version == 2) { subMessage.SilSupplement = _BitStream.ReadBit(); subMessage.IsRebroadcast = _BitStream.ReadBit(); } } } }
/// <summary> /// Decodes the target state and status message. /// </summary> /// <param name="message"></param> private void DecodeTargetStateAndStatus(AdsbMessage message) { message.MessageFormat = MessageFormat.TargetStateAndStatus; var subMessage = message.TargetStateAndStatus = new TargetStateAndStatusMessage(); subMessage.TargetStateAndStatusType = (TargetStateAndStatusType)_BitStream.ReadByte(2); switch (subMessage.TargetStateAndStatusType) { case TargetStateAndStatusType.Version1: var verticalDataSource = (VerticalDataSource)_BitStream.ReadByte(2); var altitudeIsMeanSeaLevel = _BitStream.ReadBit(); if (!_BitStream.ReadBit()) // backwards compatibility bit - if this is non-zero then it's a version 0 TCP message that we need to ignore { var version1 = subMessage.Version1 = new TargetStateAndStatusVersion1(); version1.VerticalDataSource = verticalDataSource; version1.AltitudesAreMeanSeaLevel = altitudeIsMeanSeaLevel; version1.TargetAltitudeCapability = (TargetAltitudeCapability)_BitStream.ReadByte(2); version1.VerticalModeIndicator = (VerticalModeIndicator)_BitStream.ReadByte(2); var altitude = (int)_BitStream.ReadUInt16(10); if (version1.VerticalDataSource != VerticalDataSource.None && altitude < 1011) { version1.TargetAltitude = (altitude * 100) - 1000; } version1.HorizontalDataSource = (HorizontalDataSource)_BitStream.ReadByte(2); var heading = _BitStream.ReadUInt16(9); if (version1.HorizontalDataSource != HorizontalDataSource.None && heading < 360) { version1.TargetHeading = (short)heading; } version1.TargetHeadingIsTrack = _BitStream.ReadBit(); version1.HorizontalModeIndicator = (HorizontalModeIndicator)_BitStream.ReadByte(2); version1.NacP = _BitStream.ReadByte(4); version1.NicBaro = _BitStream.ReadBit(); version1.Sil = _BitStream.ReadByte(2); _BitStream.Skip(5); version1.TcasCapabilityMode = (TcasCapabilityMode)_BitStream.ReadByte(2); version1.EmergencyState = (EmergencyState)_BitStream.ReadByte(3); } break; case TargetStateAndStatusType.Version2: var version2 = message.TargetStateAndStatus.Version2 = new TargetStateAndStatusVersion2(); version2.SilSupplement = _BitStream.ReadBit(); version2.SelectedAltitudeIsFms = _BitStream.ReadBit(); var selAltitude = _BitStream.ReadUInt16(11); if (selAltitude != 0) { version2.SelectedAltitude = (selAltitude - 1) * 32; } var pressure = _BitStream.ReadUInt16(9); if (pressure != 0) { version2.BarometricPressureSetting = (((float)pressure - 1F) * 0.8F) + 800F; } bool headingIsValid = _BitStream.ReadBit(); var headingValue = _BitStream.ReadUInt16(9); if (headingIsValid) { version2.SelectedHeading = (double)headingValue * 0.703125; } version2.NacP = _BitStream.ReadByte(4); version2.NicBaro = _BitStream.ReadBit(); version2.Sil = _BitStream.ReadByte(2); var autopilotValid = _BitStream.ReadBit(); version2.IsAutopilotEngaged = _BitStream.ReadBit(); version2.IsVnavEngaged = _BitStream.ReadBit(); version2.IsAltitudeHoldActive = _BitStream.ReadBit(); version2.IsRebroadcast = _BitStream.ReadBit(); version2.IsApproachModeActive = _BitStream.ReadBit(); version2.IsTcasOperational = _BitStream.ReadBit(); version2.IsLnavEngaged = _BitStream.ReadBit(); if (!autopilotValid) { version2.IsAutopilotEngaged = version2.IsVnavEngaged = version2.IsAltitudeHoldActive = version2.IsApproachModeActive = version2.IsLnavEngaged = null; } break; } }
/// <summary> /// Decodes an aircraft status message. /// </summary> /// <param name="message"></param> private void DecodeAircraftStatus(AdsbMessage message) { message.MessageFormat = MessageFormat.AircraftStatus; var subMessage = message.AircraftStatus = new AircraftStatusMessage(); subMessage.AircraftStatusType = (AircraftStatusType)_BitStream.ReadByte(3); switch (subMessage.AircraftStatusType) { case AircraftStatusType.EmergencyStatus: var emergency = subMessage.EmergencyStatus = new EmergencyStatus(); emergency.EmergencyState = (EmergencyState)_BitStream.ReadByte(3); var modeA = (short)_BitStream.ReadUInt16(13); if (modeA != 0) { emergency.Squawk = ModeS.ModeATranslator.DecodeModeA(modeA); } break; case AircraftStatusType.TcasResolutionAdvisoryBroadcast: var tcas = subMessage.TcasResolutionAdvisory = new TcasResolutionAdvisory(); var araCoding = _BitStream.ReadBit(); var araValue = (short)_BitStream.ReadUInt16(13); tcas.ResolutionAdvisoryComplement = (ResolutionAdvisoryComplement)_BitStream.ReadByte(4); tcas.ResolutionAdvisoryTerminated = _BitStream.ReadBit(); tcas.MultipleThreatEncounter = _BitStream.ReadBit(); if (araCoding) { tcas.SingleThreatResolutionAdvisory = (SingleThreatResolutionAdvisory)araValue; } else if (tcas.MultipleThreatEncounter) { tcas.MultipleThreatResolutionAdvisory = (MultipleThreatResolutionAdvisory)araValue; } switch (_BitStream.ReadByte(2)) { case 1: tcas.ThreatIcao24 = (int)_BitStream.ReadUInt32(24); break; case 2: var threatAltitude = _BitStream.ReadUInt16(13); var threatRange = _BitStream.ReadByte(7); var threatBearing = _BitStream.ReadByte(6); var strippedAltitude = ((threatAltitude & 0x1F80) >> 2) | ((threatAltitude & 0x20) >> 1) | (threatAltitude & 0x0f); tcas.ThreatAltitude = ModeSAltitudeConversion.LookupGillhamAltitude(strippedAltitude); if (threatRange > 0) { tcas.ThreatRange = ((float)(threatRange - 1) / 10F) + 0.05F; tcas.ThreatRangeExceeded = threatRange == 127; } if (threatBearing > 0 && threatBearing < 61) { tcas.ThreatBearing = (short)((threatBearing - 1) * 6); } break; } break; } }
/// <summary> /// Decodes an airborne velocity message. /// </summary> /// <param name="message"></param> private void DecodeVelocity(AdsbMessage message) { message.MessageFormat = MessageFormat.AirborneVelocity; var subMessage = message.AirborneVelocity = new AirborneVelocityMessage(); var velocityType = _BitStream.ReadByte(3); subMessage.VelocityType = (VelocityType)velocityType; if (velocityType > 0 && velocityType < 5) { subMessage.ChangeOfIntent = _BitStream.ReadBit(); _BitStream.Skip(1); switch (_BitStream.ReadByte(3)) { case 0: subMessage.HorizontalVelocityError = 10F; break; case 1: subMessage.HorizontalVelocityError = -10F; break; case 2: subMessage.HorizontalVelocityError = -3F; break; case 3: subMessage.HorizontalVelocityError = -1F; break; case 4: subMessage.HorizontalVelocityError = -0.3F; break; } if (velocityType == 3 || velocityType == 4) { var headingAvailable = _BitStream.ReadBit(); var heading = _BitStream.ReadUInt16(10); if (headingAvailable) { subMessage.Heading = (double)heading * 0.3515625; } subMessage.AirspeedIsTrueAirspeed = _BitStream.ReadBit(); var airspeed = _BitStream.ReadUInt16(10); if (airspeed != 0) { if (airspeed == 1023) { subMessage.AirspeedExceeded = true; } subMessage.Airspeed = airspeed - 1; if (velocityType == 4) { subMessage.Airspeed *= 4; } } } else { var vector = subMessage.VectorVelocity = new VectorVelocity() { IsWesterlyVelocity = _BitStream.ReadBit(), EastWestVelocity = (short?)_BitStream.ReadUInt16(10), IsSoutherlyVelocity = _BitStream.ReadBit(), NorthSouthVelocity = (short?)_BitStream.ReadUInt16(10), }; if (vector.EastWestVelocity == 0) { vector.EastWestVelocity = null; } else { vector.EastWestExceeded = vector.EastWestVelocity == 1023; vector.EastWestVelocity = (short)((vector.EastWestVelocity - 1) * (velocityType == 1 ? 1 : 4)); } if (vector.NorthSouthVelocity == 0) { vector.NorthSouthVelocity = null; } else { vector.NorthSouthExceeded = vector.NorthSouthVelocity == 1023; vector.NorthSouthVelocity = (short)((vector.NorthSouthVelocity - 1) * (velocityType == 1 ? 1 : 4)); } } subMessage.VerticalRateIsBarometric = _BitStream.ReadBit(); var verticalRateSign = _BitStream.ReadBit() ? -1 : 1; var verticalRate = _BitStream.ReadUInt16(9); if (verticalRate != 0) { subMessage.VerticalRateExceeded = verticalRateSign == 511; subMessage.VerticalRate = verticalRateSign * ((verticalRate - 1) * 64); } _BitStream.Skip(2); var geometricDeltaSign = _BitStream.ReadBit() ? -1 : 1; var geometricDelta = _BitStream.ReadByte(7); if (geometricDelta != 0) { subMessage.GeometricAltitudeDeltaExceeded = geometricDelta == 127; subMessage.GeometricAltitudeDelta = (short)(geometricDeltaSign * ((geometricDelta - 1) * 25)); } } }
/// <summary> /// See interface docs. /// </summary> /// <param name="modeSMessage"></param> /// <returns></returns> public AdsbMessage Translate(ModeSMessage modeSMessage) { if (Statistics == null) { throw new InvalidOperationException("Statistics must be supplied before Translate can be called"); } AdsbMessage result = null; if (modeSMessage != null && modeSMessage.ExtendedSquitterMessage != null && modeSMessage.ExtendedSquitterMessage.Length == 7) { _BitStream.Initialise(modeSMessage.ExtendedSquitterMessage); result = new AdsbMessage(modeSMessage); result.ModeSMessage.Identity = modeSMessage.Identity; if (IsCoarseFormatTisb(result)) { DecodeCoarseTisbAirbornePosition(result); } else { result.Type = _BitStream.ReadByte(5); switch (result.Type) { case 0: DecodeAirbornePosition(result); break; case 1: case 2: case 3: case 4: DecodeIdentification(result); break; case 5: case 6: case 7: case 8: DecodeSurfacePosition(result); break; case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: DecodeAirbornePosition(result); break; case 19: DecodeVelocity(result); break; case 20: case 21: case 22: DecodeAirbornePosition(result); break; case 28: DecodeAircraftStatus(result); break; case 29: DecodeTargetStateAndStatus(result); break; case 31: DecodeAircraftOperationalStatus(result); break; } } if (Statistics != null) { Statistics.Lock(r => { ++r.AdsbCount; ++r.AdsbMessageFormatCount[(int)result.MessageFormat]; ++r.AdsbTypeCount[result.Type]; }); } } else { result = new AdsbMessage(modeSMessage); } return(result); }