コード例 #1
0
        public void TestInitialise()
        {
            _OriginalClassFactory = Factory.TakeSnapshot();

            _HeartbeatService = TestUtilities.CreateMockSingleton<IHeartbeatService>();
            _StandingDataManager = TestUtilities.CreateMockSingleton<IStandingDataManager>();
            _StandingDataManager.Setup(r => r.FindCodeBlock(It.IsAny<string>())).Returns(new CodeBlock() { Country = "X" });
            _StandingDataManager.Setup(r => r.CodeBlocksLoaded).Returns(true);

            _Statistics = Factory.Singleton.Resolve<IStatistics>().Singleton;
            _Statistics.Initialise();
            _Statistics.ResetConnectionStatistics();
            _Statistics.ResetMessageCounters();

            _Translator = Factory.Singleton.Resolve<IRawMessageTranslator>();
            _Provider = new Mock<IRawMessageTranslatorProvider>() { DefaultValue = DefaultValue.Mock }.SetupAllProperties();
            _Provider.Setup(r => r.UtcNow).Returns(new DateTime(1999, 12, 31));
            _Translator.Provider = _Provider.Object;

            _PositionResetEvent = new EventRecorder<EventArgs<string>>();
            _Translator.PositionReset += _PositionResetEvent.Handler;

            _NowUtc = new DateTime(2012, 1, 2, 3, 4, 5, 6);
            _ModeSMessage = new ModeSMessage() { DownlinkFormat = DownlinkFormat.AllCallReply, Icao24 = 0x112233, ParityInterrogatorIdentifier = 0 };
            _AdsbMessage = new AdsbMessage(_ModeSMessage);

            _RandomIcaos = new List<int>();
        }
コード例 #2
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);
 }
コード例 #3
0
        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());
        }
コード例 #4
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;
            }
        }
コード例 #5
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(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);
        }
コード例 #6
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();
                    }
                }
            }
        }
コード例 #7
0
 private void ApplyAdsbAircraftStatus(AdsbMessage adsbMessage, BaseStationMessage baseStationMessage)
 {
     if(adsbMessage.AircraftStatus.EmergencyStatus != null) {
         baseStationMessage.Squawk = adsbMessage.AircraftStatus.EmergencyStatus.Squawk;
         baseStationMessage.Emergency = adsbMessage.AircraftStatus.EmergencyStatus.EmergencyState != EmergencyState.None;
     }
 }
コード例 #8
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;
        }
コード例 #9
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;
            }
        }
コード例 #10
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;
        }
コード例 #11
0
        /// <summary>
        /// Creates a BaseStationMessage from the Mode-S and ADS-B message passed across.
        /// </summary>
        /// <param name="messageReceivedUtc"></param>
        /// <param name="modeSMessage"></param>
        /// <param name="adsbMessage"></param>
        /// <param name="trackedAircraft"></param>
        /// <returns></returns>
        private BaseStationMessage CreateBaseStationMessage(DateTime messageReceivedUtc, ModeSMessage modeSMessage, AdsbMessage adsbMessage, TrackedAircraft trackedAircraft)
        {
            var result = new BaseStationMessage() {
                MessageType = BaseStationMessageType.Transmission,
                TransmissionType = ConvertToTransmissionType(modeSMessage, adsbMessage),
                MessageGenerated = messageReceivedUtc,
                MessageLogged = messageReceivedUtc,
                Icao24 = modeSMessage.FormattedIcao24,
                Altitude = modeSMessage.Altitude,
                Squawk = modeSMessage.Identity,
            };

            ApplyModeSValues(modeSMessage, trackedAircraft, result);
            if(adsbMessage != null) ApplyAdsbValues(messageReceivedUtc, adsbMessage, trackedAircraft, result);

            result.GroundSpeed = Round.GroundSpeed(result.GroundSpeed);
            result.Track = Round.Track(result.Track);
            result.Latitude = Round.Coordinate(result.Latitude);
            result.Longitude = Round.Coordinate(result.Longitude);

            return result;
        }
コード例 #12
0
        public void RawMessageTranslator_Translate_Extracts_Position_From_ADSB_Messages_Correctly()
        {
            var worksheet = new ExcelWorksheetData(TestContext);

            _Translator.ReceiverLocation = ParseGlobalPosition(worksheet.String("ReceiverPosn"));
            _Translator.ReceiverRangeKilometres = worksheet.Int("Range");
            _Translator.GlobalDecodeAirborneThresholdMilliseconds = worksheet.Int("GATS");
            _Translator.GlobalDecodeFastSurfaceThresholdMilliseconds = worksheet.Int("GFSTS");
            _Translator.GlobalDecodeSlowSurfaceThresholdMilliseconds = worksheet.Int("GSSTS");
            _Translator.LocalDecodeMaxSpeedAirborne = worksheet.Double("LAMS");
            _Translator.LocalDecodeMaxSpeedTransition = worksheet.Double("LTMS");
            _Translator.LocalDecodeMaxSpeedSurface = worksheet.Double("LSMS");
            _Translator.SuppressReceiverRangeCheck = worksheet.Bool("SRRC");
            _Translator.UseLocalDecodeForInitialPosition = worksheet.Bool("ULD");

            DateTime now = DateTime.UtcNow;
            for(var i = 1;i <= 4;++i) {
                var millisecondsColumn = String.Format("MSec{0}", i);
                var cprColumn = String.Format("CPR{0}", i);
                var speedColumn = String.Format("Spd{0}", i);
                var positionColumn = String.Format("Posn{0}", i);

                if(worksheet.String(cprColumn) == null) continue;
                var cpr = ParseCpr(worksheet.String(cprColumn));
                var speed = worksheet.NDouble(speedColumn);
                var expectedPosition = ParseGlobalPosition(worksheet.String(positionColumn));

                if(i != 1 && worksheet.String(millisecondsColumn) != null) {
                    now = now.AddMilliseconds(worksheet.Int(millisecondsColumn));
                }

                var modeSMessage = new ModeSMessage() { DownlinkFormat = DownlinkFormat.ExtendedSquitter, Icao24 = 0x112233, ParityInterrogatorIdentifier = 0 };
                var adsbMessage = new AdsbMessage(modeSMessage);
                switch(cpr.NumberOfBits) {
                    case 17:
                        adsbMessage.MessageFormat = MessageFormat.AirbornePosition;
                        adsbMessage.AirbornePosition = new AirbornePositionMessage() { CompactPosition = cpr };
                        break;
                    case 19:
                        adsbMessage.MessageFormat = MessageFormat.SurfacePosition;
                        adsbMessage.SurfacePosition = new SurfacePositionMessage() { CompactPosition = cpr, GroundSpeed = speed, };
                        break;
                }

                var baseStationMessage = _Translator.Translate(now, modeSMessage, adsbMessage);

                var failMessage = String.Format("Failed on message {0}", i);
                if(expectedPosition == null) {
                    if(baseStationMessage != null) {
                        if(baseStationMessage.Latitude != null || baseStationMessage.Longitude != null) {
                            Assert.Fail(String.Format("Position decoded to {0}/{1} erroneously. {2}", baseStationMessage.Latitude, baseStationMessage.Longitude, failMessage));
                        }
                    }
                } else {
                    Assert.IsNotNull(baseStationMessage.Latitude, failMessage);
                    Assert.IsNotNull(baseStationMessage.Longitude, failMessage);
                    Assert.AreEqual(expectedPosition.Latitude, baseStationMessage.Latitude.Value, 0.0001, failMessage);
                    Assert.AreEqual(expectedPosition.Longitude, baseStationMessage.Longitude.Value, 0.0001, failMessage);
                }
            }

            Assert.AreEqual(worksheet.Int("ResetCount"), _PositionResetEvent.CallCount);
            Assert.AreEqual(worksheet.Int("ResetCount") > 0 ? 1L : 0L, _Statistics.AdsbPositionsReset);
            Assert.AreEqual(worksheet.Long("BadRange"), _Statistics.AdsbPositionsOutsideRange);
            Assert.AreEqual(worksheet.Long("BadSpeed"), _Statistics.AdsbPositionsExceededSpeedCheck);
        }
コード例 #13
0
 /// <summary>
 /// Applies values from the ADS-B message to the BaseStation message being formed.
 /// </summary>
 /// <param name="messageReceivedUtc"></param>
 /// <param name="adsbMessage"></param>
 /// <param name="trackedAircraft"></param>
 /// <param name="baseStationMessage"></param>
 private void ApplyAdsbValues(DateTime messageReceivedUtc, AdsbMessage adsbMessage, TrackedAircraft trackedAircraft, BaseStationMessage baseStationMessage)
 {
     if(adsbMessage.AirbornePosition != null)        ApplyAdsbAirbornePosition(messageReceivedUtc, adsbMessage, trackedAircraft, baseStationMessage);
     if(adsbMessage.AirborneVelocity != null)        ApplyAdsbAirborneVelocity(adsbMessage, baseStationMessage);
     if(adsbMessage.AircraftStatus != null)          ApplyAdsbAircraftStatus(adsbMessage, baseStationMessage);
     if(adsbMessage.IdentifierAndCategory != null)   ApplyAdsbIdentifierAndCategory(adsbMessage, trackedAircraft, baseStationMessage);
     if(adsbMessage.SurfacePosition != null)         ApplyAdsbSurfacePosition(messageReceivedUtc, adsbMessage, trackedAircraft, baseStationMessage);
     if(adsbMessage.TargetStateAndStatus != null)    ApplyAdsbTargetStateAndStatus(adsbMessage, baseStationMessage);
 }
コード例 #14
0
        /// <summary>
        /// Returns the transmission type corresponding to raw messages passed across.
        /// </summary>
        /// <param name="modeSMessage"></param>
        /// <param name="adsbMessage"></param>
        /// <returns></returns>
        private BaseStationTransmissionType ConvertToTransmissionType(ModeSMessage modeSMessage, AdsbMessage adsbMessage)
        {
            BaseStationTransmissionType result = BaseStationTransmissionType.None;

            if(adsbMessage == null) {
                switch(modeSMessage.DownlinkFormat) {
                    case DownlinkFormat.CommBAltitudeReply:
                    case DownlinkFormat.SurveillanceAltitudeReply:          result = BaseStationTransmissionType.SurveillanceAlt; break;
                    case DownlinkFormat.CommBIdentityReply:
                    case DownlinkFormat.SurveillanceIdentityReply:          result = BaseStationTransmissionType.SurveillanceId; break;
                    case DownlinkFormat.CommD:
                    case DownlinkFormat.ExtendedSquitter:
                    case DownlinkFormat.ExtendedSquitterNonTransponder:
                    case DownlinkFormat.MilitaryExtendedSquitter:
                    case DownlinkFormat.AllCallReply:                       result = BaseStationTransmissionType.AllCallReply; break;
                    case DownlinkFormat.LongAirToAirSurveillance:
                    case DownlinkFormat.ShortAirToAirSurveillance:          result = BaseStationTransmissionType.AirToAir; break;
                    default:                                                throw new NotImplementedException();
                }
            } else {
                switch(adsbMessage.MessageFormat) {
                    case MessageFormat.AirbornePosition:                    result = BaseStationTransmissionType.AirbornePosition; break;
                    case MessageFormat.AirborneVelocity:                    result = BaseStationTransmissionType.AirborneVelocity; break;
                    case MessageFormat.IdentificationAndCategory:           result = BaseStationTransmissionType.IdentificationAndCategory; break;
                    case MessageFormat.SurfacePosition:                     result = BaseStationTransmissionType.SurfacePosition; break;
                    case MessageFormat.AircraftOperationalStatus:
                    case MessageFormat.AircraftStatus:
                    case MessageFormat.None:
                    case MessageFormat.NoPositionInformation:
                    case MessageFormat.TargetStateAndStatus:                result = BaseStationTransmissionType.AllCallReply; break;
                }
            }

            return result;
        }
コード例 #15
0
 private void ApplyAdsbTargetStateAndStatus(AdsbMessage adsbMessage, BaseStationMessage baseStationMessage)
 {
     if(adsbMessage.TargetStateAndStatus.Version1 != null) {
         baseStationMessage.Emergency = adsbMessage.TargetStateAndStatus.Version1.EmergencyState != EmergencyState.None;
     }
 }
コード例 #16
0
        private void ApplyAdsbSurfacePosition(DateTime messageReceivedUtc, AdsbMessage adsbMessage, TrackedAircraft trackedAircraft, BaseStationMessage baseStationMessage)
        {
            baseStationMessage.OnGround = true;
            baseStationMessage.GroundSpeed = (float?)adsbMessage.SurfacePosition.GroundSpeed;
            baseStationMessage.Track = (float?)adsbMessage.SurfacePosition.GroundTrack;
            if(adsbMessage.SurfacePosition.IsReversing) {
                if(baseStationMessage.Supplementary == null) baseStationMessage.Supplementary = new BaseStationSupplementaryMessage();
                baseStationMessage.Supplementary.SpeedType = SpeedType.GroundSpeedReversing;
            }

            if(adsbMessage.SurfacePosition.CompactPosition != null) {
                trackedAircraft.RecordMessage(messageReceivedUtc, adsbMessage.SurfacePosition.CompactPosition);
                DecodePosition(baseStationMessage, trackedAircraft, adsbMessage.SurfacePosition.GroundSpeed);
            }
        }
コード例 #17
0
 private void ApplyAdsbIdentifierAndCategory(AdsbMessage adsbMessage, TrackedAircraft trackedAircraft, BaseStationMessage baseStationMessage)
 {
     if(adsbMessage.IdentifierAndCategory.Identification != null) {
         trackedAircraft.SeenAdsbCallsign = true;
         baseStationMessage.Callsign = adsbMessage.IdentifierAndCategory.Identification.Trim();
         if(baseStationMessage.Supplementary == null) baseStationMessage.Supplementary = new BaseStationSupplementaryMessage();
         baseStationMessage.Supplementary.CallsignIsSuspect = false;
     }
 }
コード例 #18
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);
        }
コード例 #19
0
        /// <summary>
        /// See interface docs.
        /// </summary>
        /// <param name="messageReceivedUtc"></param>
        /// <param name="modeSMessage"></param>
        /// <param name="adsbMessage"></param>
        /// <returns></returns>
        public BaseStationMessage Translate(DateTime messageReceivedUtc, ModeSMessage modeSMessage, AdsbMessage adsbMessage)
        {
            BaseStationMessage result = null;

            if(modeSMessage != null && !_Disposed) {
                var isValidMessage = DetermineWhetherValid(modeSMessage, messageReceivedUtc);

                if(isValidMessage) {
                    TrackedAircraft trackedAircraft;
                    lock(_TrackedAircraftLock) {
                        if(!_TrackedAircraft.TryGetValue(modeSMessage.Icao24, out trackedAircraft)) {
                            trackedAircraft = new TrackedAircraft() { Icao24 = modeSMessage.FormattedIcao24, LatestMessageUtc = messageReceivedUtc, };
                            _TrackedAircraft.Add(modeSMessage.Icao24, trackedAircraft);
                        } else {
                            if((messageReceivedUtc - trackedAircraft.LatestMessageUtc).TotalSeconds >= TrackingTimeoutSeconds) {
                                trackedAircraft = new TrackedAircraft() { Icao24 = modeSMessage.FormattedIcao24 };
                                _TrackedAircraft[modeSMessage.Icao24] = trackedAircraft;
                            }
                            trackedAircraft.LatestMessageUtc = messageReceivedUtc;
                        }
                    }

                    if(isValidMessage) {
                        result = CreateBaseStationMessage(messageReceivedUtc, modeSMessage, adsbMessage, trackedAircraft);
                        if(_Statistics.Lock != null) { lock(_Statistics.Lock) _Statistics.AdsbAircraftTracked = _TrackedAircraft.Count; }
                    }
                }
            }

            return result;
        }
コード例 #20
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);
        }
コード例 #21
0
        private void ApplyAdsbAirbornePosition(DateTime messageReceivedUtc, AdsbMessage adsbMessage, TrackedAircraft trackedAircraft, BaseStationMessage baseStationMessage)
        {
            if(adsbMessage.AirbornePosition.BarometricAltitude != null) baseStationMessage.Altitude = adsbMessage.AirbornePosition.BarometricAltitude;
            else if(adsbMessage.AirbornePosition.GeometricAltitude != null) {
                baseStationMessage.Altitude = adsbMessage.AirbornePosition.GeometricAltitude;
                if(baseStationMessage.Supplementary == null) baseStationMessage.Supplementary = new BaseStationSupplementaryMessage();
                baseStationMessage.Supplementary.AltitudeIsGeometric = true;
            }

            if(adsbMessage.AirbornePosition.CompactPosition != null) {
                trackedAircraft.RecordMessage(messageReceivedUtc, adsbMessage.AirbornePosition.CompactPosition);
                DecodePosition(baseStationMessage, trackedAircraft, null);
            }

            baseStationMessage.SquawkHasChanged = adsbMessage.AirbornePosition.SurveillanceStatus == SurveillanceStatus.TemporaryAlert;
            baseStationMessage.IdentActive = adsbMessage.AirbornePosition.SurveillanceStatus == SurveillanceStatus.SpecialPositionIdentification;
        }
コード例 #22
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));
                }
            }
        }
コード例 #23
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;
 }
コード例 #24
0
        public void TestInitialise()
        {
            _Statistics = Factory.Singleton.Resolve<IStatistics>().Singleton;
            _Statistics.Initialise();
            _Statistics.ResetConnectionStatistics();
            _Statistics.ResetMessageCounters();

            _OriginalClassFactory = Factory.TakeSnapshot();

            _RuntimeEnvironment = TestUtilities.CreateMockSingleton<IRuntimeEnvironment>();
            _RuntimeEnvironment.Setup(r => r.IsTest).Returns(true);

            _Port30003Translator = TestUtilities.CreateMockImplementation<IBaseStationMessageTranslator>();
            _ModeSTranslator = TestUtilities.CreateMockImplementation<IModeSTranslator>();
            _AdsbTranslator = TestUtilities.CreateMockImplementation<IAdsbTranslator>();
            _RawMessageTranslator = new Mock<IRawMessageTranslator>(MockBehavior.Default) { DefaultValue = DefaultValue.Mock };
            _ModeSParity = TestUtilities.CreateMockImplementation<IModeSParity>();
            _ModeSMessage = new ModeSMessage();
            _AdsbMessage = new AdsbMessage(_ModeSMessage);
            _Port30003Message = new BaseStationMessage();
            _Port30003Translator.Setup(r => r.Translate(It.IsAny<string>())).Returns(_Port30003Message);
            _AdsbTranslator.Setup(r => r.Translate(It.IsAny<ModeSMessage>())).Returns(_AdsbMessage);
            _ModeSTranslator.Setup(r => r.Translate(It.IsAny<byte[]>())).Returns(_ModeSMessage);
            _ModeSTranslator.Setup(r => r.Translate(It.IsAny<byte[]>(), It.IsAny<int>())).Returns(_ModeSMessage);
            _RawMessageTranslator.Setup(r => r.Translate(It.IsAny<DateTime>(), It.IsAny<ModeSMessage>(), It.IsAny<AdsbMessage>())).Returns(_Port30003Message);

            _Listener = Factory.Singleton.Resolve<IListener>();
            _Provider = new MockListenerProvider();
            _BytesExtractor = new MockMessageBytesExtractor();

            _ExceptionCaughtEvent = new EventRecorder<EventArgs<Exception>>();
            _ConnectionStateChangedEvent = new EventRecorder<EventArgs>();
            _ModeSMessageReceivedEvent = new EventRecorder<ModeSMessageEventArgs>();
            _Port30003MessageReceivedEvent = new EventRecorder<BaseStationMessageEventArgs>();
            _SourceChangedEvent = new EventRecorder<EventArgs>();

            _Listener.ConnectionStateChanged += _ConnectionStateChangedEvent.Handler;
            _Listener.ExceptionCaught += _ExceptionCaughtEvent.Handler;
            _Listener.ModeSMessageReceived += _ModeSMessageReceivedEvent.Handler;
            _Listener.Port30003MessageReceived += _Port30003MessageReceivedEvent.Handler;
            _Listener.SourceChanged += _SourceChangedEvent.Handler;

            _ExceptionCaughtEvent.EventRaised += DefaultExceptionCaughtHandler;
        }
コード例 #25
0
        private void ApplyAdsbAirborneVelocity(AdsbMessage adsbMessage, BaseStationMessage baseStationMessage)
        {
            if(adsbMessage.AirborneVelocity.VectorVelocity != null) {
                baseStationMessage.GroundSpeed = (float?)adsbMessage.AirborneVelocity.VectorVelocity.Speed;
                baseStationMessage.Track = (float?)adsbMessage.AirborneVelocity.VectorVelocity.Bearing;
            } else if(adsbMessage.AirborneVelocity.VelocityType == VelocityType.AirspeedSubsonic || adsbMessage.AirborneVelocity.VelocityType == VelocityType.AirspeedSupersonic) {
                baseStationMessage.GroundSpeed = (float?)adsbMessage.AirborneVelocity.Airspeed;
                baseStationMessage.Track = (float?)adsbMessage.AirborneVelocity.Heading;

                if(baseStationMessage.Supplementary == null) baseStationMessage.Supplementary = new BaseStationSupplementaryMessage();
                baseStationMessage.Supplementary.SpeedType = adsbMessage.AirborneVelocity.AirspeedIsTrueAirspeed ? SpeedType.TrueAirSpeed : SpeedType.IndicatedAirSpeed;
                baseStationMessage.Supplementary.TrackIsHeading = true;
            }

            baseStationMessage.VerticalRate = adsbMessage.AirborneVelocity.VerticalRate;
            if(adsbMessage.AirborneVelocity.VerticalRateIsBarometric) {
                if(baseStationMessage.Supplementary == null) baseStationMessage.Supplementary = new BaseStationSupplementaryMessage();
                baseStationMessage.Supplementary.VerticalRateIsGeometric = true;
            }
        }