Пример #1
0
        /// <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);
        }
Пример #2
0
        /// <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);
        }
Пример #3
0
        /// <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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        /// <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);
        }
Пример #6
0
        /// <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);
        }
Пример #7
0
        /// <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;
            }
        }
Пример #8
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());
        }
Пример #10
0
        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;
            }
        }
Пример #11
0
 /// <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;
 }
Пример #12
0
        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);
            }
        }
Пример #13
0
        /// <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);
        }
Пример #14
0
 /// <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);
 }
Пример #15
0
        /// <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();
                    }
                }
            }
        }
Пример #16
0
        /// <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;
            }
        }
Пример #17
0
        /// <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;
            }
        }
Пример #18
0
        /// <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));
                }
            }
        }
Пример #19
0
        /// <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);
        }