public void BaseStationMessageTranslator_Translate_Translates_Messages_Correctly()
        {
            ExcelWorksheetData worksheet = new ExcelWorksheetData(TestContext);

            BaseStationMessage translated = _Implementation.Translate(worksheet.String("Text"), 123);

            Assert.AreEqual(Enum.Parse(typeof(BaseStationMessageType), worksheet.String("MessageType")), translated.MessageType);
            Assert.AreEqual(Enum.Parse(typeof(BaseStationTransmissionType), worksheet.String("TransmissionType")), translated.TransmissionType);
            Assert.AreEqual(Enum.Parse(typeof(BaseStationStatusCode), worksheet.String("StatusCode")), translated.StatusCode);
            Assert.AreEqual(worksheet.Int("SessionId"), translated.SessionId);
            Assert.AreEqual(worksheet.Int("AircraftId"), translated.AircraftId);
            Assert.AreEqual(worksheet.String("Icao24"), translated.Icao24);
            Assert.AreEqual(worksheet.Int("FlightId"), translated.FlightId);
            Assert.AreEqual(worksheet.DateTime("MessageGenerated"), translated.MessageGenerated);
            Assert.AreEqual(worksheet.DateTime("MessageLogged"), translated.MessageLogged);
            Assert.AreEqual(worksheet.String("Callsign"), translated.Callsign);
            Assert.AreEqual(worksheet.NFloat("Altitude"), translated.Altitude);
            Assert.AreEqual(worksheet.NFloat("GroundSpeed"), translated.GroundSpeed);
            Assert.AreEqual(worksheet.NFloat("Track"), translated.Track);
            Assert.AreEqual(worksheet.NDouble("Latitude"), translated.Latitude);
            Assert.AreEqual(worksheet.NDouble("Longitude"), translated.Longitude);
            Assert.AreEqual(worksheet.NFloat("VerticalRate"), translated.VerticalRate);
            Assert.AreEqual(worksheet.NInt("Squawk"), translated.Squawk);
            Assert.AreEqual(worksheet.NBool("SquawkHasChanged"), translated.SquawkHasChanged);
            Assert.AreEqual(worksheet.NBool("Emergency"), translated.Emergency);
            Assert.AreEqual(worksheet.NBool("IdentActive"), translated.IdentActive);
            Assert.AreEqual(worksheet.NBool("OnGround"), translated.OnGround);
            Assert.AreEqual(worksheet.Bool("IsMlat"), translated.IsMlat);
        }
 public void BaseStationMessageTranslator_Translate_Ignores_TransmissionType_For_All_NonTransmission_Messages()
 {
     foreach (BaseStationMessageType messageType in Enum.GetValues(typeof(BaseStationMessageType)))
     {
         if (messageType == BaseStationMessageType.Unknown)
         {
             continue;
         }
         foreach (BaseStationTransmissionType transmissionType in Enum.GetValues(typeof(BaseStationTransmissionType)))
         {
             if (transmissionType == BaseStationTransmissionType.None)
             {
                 continue;
             }
             string text = String.Format("{0},{1},5,2056,7404F2,11267,2008/11/28,23:48:18.611,2008/11/28,23:53:19.161,,,,,,,,,,,,",
                                         BaseStationMessageHelper.ConvertToString(messageType),
                                         BaseStationMessageHelper.ConvertToString(transmissionType));
             string             errorText = String.Format("{0} and {1}", messageType, transmissionType);
             BaseStationMessage message   = _Implementation.Translate(text, 123);
             if (messageType == BaseStationMessageType.Transmission)
             {
                 Assert.AreEqual(transmissionType, message.TransmissionType, errorText);
             }
             else
             {
                 Assert.AreEqual(BaseStationTransmissionType.None, message.TransmissionType, errorText);
             }
         }
     }
 }
Пример #3
0
 /// <summary>
 /// Returns false if the message doesn't carry useful information and can be discarded.
 /// </summary>
 /// <param name="message"></param>
 /// <returns></returns>
 private static bool IsMeaningfulMessage(BaseStationMessage message)
 {
     return(message.MessageType == BaseStationMessageType.Transmission &&
            message.TransmissionType != BaseStationTransmissionType.AllCallReply &&
            message.TransmissionType != BaseStationTransmissionType.None &&
            message.Icao24 != null && message.Icao24.Length == 6);
 }
Пример #4
0
        public void TestInitialise()
        {
            _Server   = Factory.Singleton.Resolve <IRebroadcastServer>();
            _Listener = new Mock <IListener>(MockBehavior.Default)
            {
                DefaultValue = DefaultValue.Mock
            }.SetupAllProperties();

            _BroadcastProvider = new Mock <IBroadcastProvider>(MockBehavior.Default)
            {
                DefaultValue = DefaultValue.Mock
            }.SetupAllProperties();
            _SentBytes = new List <byte[]>();
            _BroadcastProvider.Setup(r => r.Send(It.IsAny <byte[]>())).Callback((byte[] bytes) => _SentBytes.Add(bytes));

            _Server.Listener          = _Listener.Object;
            _Server.BroadcastProvider = _BroadcastProvider.Object;

            _ExceptionCaughtEvent              = new EventRecorder <EventArgs <Exception> >();
            _ExceptionCaughtEvent.EventRaised += DefaultExceptionCaughtHandler;
            _OnlineChangedEvent      = new EventRecorder <EventArgs>();
            _Server.ExceptionCaught += _ExceptionCaughtEvent.Handler;
            _Server.OnlineChanged   += _OnlineChangedEvent.Handler;

            _Port30003Message = new BaseStationMessage()
            {
                Icao24 = "313233"
            };
        }
Пример #5
0
        /// <summary>
        /// Updates the counters of total messages for a flight.
        /// </summary>
        /// <param name="message"></param>
        /// <param name="flight"></param>
        private static void UpdateMessageCounters(BaseStationMessage message, BaseStationFlight flight)
        {
            switch (message.TransmissionType)
            {
            case BaseStationTransmissionType.IdentificationAndCategory: ++flight.NumIDMsgRec; break;

            case BaseStationTransmissionType.SurfacePosition:           ++flight.NumSurPosMsgRec; break;

            case BaseStationTransmissionType.AirbornePosition:          ++flight.NumAirPosMsgRec; break;

            case BaseStationTransmissionType.AirborneVelocity:          ++flight.NumAirVelMsgRec; break;

            case BaseStationTransmissionType.SurveillanceAlt:           ++flight.NumSurAltMsgRec; break;

            case BaseStationTransmissionType.SurveillanceId:            ++flight.NumSurIDMsgRec; break;

            case BaseStationTransmissionType.AirToAir:                  ++flight.NumAirToAirMsgRec; break;

            case BaseStationTransmissionType.AllCallReply:              ++flight.NumAirCallRepMsgRec; break;
            }

            if (message.Latitude == null && message.Longitude == null && message.GroundSpeed == null && message.Track == null && message.VerticalRate == null)
            {
                ++flight.NumModeSMsgRec;
            }
            else
            {
                ++flight.NumADSBMsgRec;
                if (message.Latitude != null && message.Longitude != null)
                {
                    ++flight.NumPosMsgRec;
                }
            }
        }
 public void BaseStationMessageTranslator_Translate_Only_Translate_Status_Codes_For_Status_Messages()
 {
     foreach (BaseStationMessageType messageType in Enum.GetValues(typeof(BaseStationMessageType)))
     {
         if (messageType == BaseStationMessageType.Unknown)
         {
             continue;
         }
         foreach (BaseStationStatusCode statusCode in Enum.GetValues(typeof(BaseStationStatusCode)))
         {
             if (statusCode == BaseStationStatusCode.None)
             {
                 continue;
             }
             string text = String.Format("{0},1,5,2056,7404F2,11267,2008/11/28,23:48:18.611,2008/11/28,23:53:19.161,{1},,,,,,,,,,,",
                                         BaseStationMessageHelper.ConvertToString(messageType),
                                         BaseStationMessageHelper.ConvertToString(statusCode));
             string             errorText = String.Format("{0} and {1}", messageType, statusCode);
             BaseStationMessage message   = _Implementation.Translate(text, 123);
             if (messageType == BaseStationMessageType.StatusChange)
             {
                 Assert.AreEqual(statusCode, message.StatusCode, errorText);
             }
             else
             {
                 Assert.AreEqual(BaseStationMessageHelper.ConvertToString(statusCode), message.Callsign, errorText);
             }
         }
     }
 }
 private void AddSupplementaryValue(BaseStationMessage message, Action <BaseStationSupplementaryMessage> setValue)
 {
     if (message.Supplementary == null)
     {
         message.Supplementary = new BaseStationSupplementaryMessage();
     }
     setValue(message.Supplementary);
 }
Пример #8
0
        /// <summary>
        /// Creates database records and updates internal objects to track an aircraft that is currently transmitting messages.
        /// </summary>
        /// <param name="message"></param>
        private void TrackFlight(BaseStationMessage message)
        {
            if (IsTransmissionMessage(message))
            {
                lock (_SyncLock) {
                    if (_Session != null)
                    {
                        var localNow = Provider.LocalNow;

                        FlightRecords flightRecords;
                        if (!_FlightMap.TryGetValue(message.Icao24, out flightRecords))
                        {
                            flightRecords = new FlightRecords();
                            _Database.StartTransaction();
                            try {
                                flightRecords.Aircraft   = FetchOrCreateAircraft(localNow, message.Icao24);
                                flightRecords.Flight     = CreateFlight(localNow, flightRecords.Aircraft.AircraftID, message.Callsign);
                                flightRecords.EndTimeUtc = Provider.UtcNow;
                                _Database.EndTransaction();
                            } catch (ThreadAbortException) {
                            } catch (Exception ex) {
                                Debug.WriteLine(String.Format("BaseStationDatabaseWriter.Plugin.TrackFlight caught exception {0}", ex.ToString()));
                                _Database.RollbackTransaction();
                                throw;
                            }
                            _FlightMap.Add(message.Icao24, flightRecords);
                        }
                        else
                        {
                            if (flightRecords.Flight.Callsign.Length == 0 && !String.IsNullOrEmpty(message.Callsign))
                            {
                                var databaseVersion = _Database.GetFlightById(flightRecords.Flight.FlightID);
                                flightRecords.Flight.Callsign = databaseVersion.Callsign = message.Callsign;
                                _Database.UpdateFlight(databaseVersion);
                            }
                        }

                        var flight = flightRecords.Flight;
                        flightRecords.EndTimeUtc = Provider.UtcNow;
                        flight.EndTime           = localNow;
                        if (message.SquawkHasChanged.GetValueOrDefault())
                        {
                            flight.HadAlert = true;
                        }
                        if (message.IdentActive.GetValueOrDefault())
                        {
                            flight.HadSpi = true;
                        }
                        if (message.Squawk == 7500 || message.Squawk == 7600 || message.Squawk == 7700)
                        {
                            flight.HadEmergency = true;
                        }
                        UpdateFirstLastValues(message, flight, flightRecords);
                        UpdateMessageCounters(message, flight);
                    }
                }
            }
        }
        public void TestInitialise()
        {
            _Compressor = Factory.Singleton.Resolve <IBaseStationMessageCompressor>();

            _Message                  = new BaseStationMessage();
            _Message.MessageType      = BaseStationMessageType.Transmission;
            _Message.TransmissionType = BaseStationTransmissionType.SurveillanceAlt;
            _Message.Icao24           = "405012";
        }
 public void BaseStationMessageTranslator_Translate_Parses_Transmission_Types_Correctly()
 {
     foreach(BaseStationTransmissionType transmissionType in Enum.GetValues(typeof(BaseStationTransmissionType))) {
         if(transmissionType == BaseStationTransmissionType.None) continue;
         string typeText = BaseStationMessageHelper.ConvertToString(transmissionType);
         BaseStationMessage message = _Implementation.Translate(String.Format("MSG,{0},5,2056,7404F2,11267,2008/11/28,23:48:18.611,2008/11/28,23:53:19.161,,,,,,,,,,,,", typeText));
         Assert.AreEqual(transmissionType, message.TransmissionType, transmissionType.ToString());
     }
 }
 public void BaseStationMessageTranslator_Translate_Parses_Status_Codes_Correctly()
 {
     foreach(BaseStationStatusCode statusCode in Enum.GetValues(typeof(BaseStationStatusCode))) {
         if(statusCode == BaseStationStatusCode.None) continue;
         string text = String.Format("STA,1,5,2056,7404F2,11267,2008/11/28,23:48:18.611,2008/11/28,23:53:19.161,{0},,,,,,,,,,,", BaseStationMessageHelper.ConvertToString(statusCode));
         BaseStationMessage message = _Implementation.Translate(text);
         Assert.AreEqual(statusCode, message.StatusCode, statusCode.ToString());
     }
 }
 public void BaseStationMessageTranslator_Translate_Parses_Message_Types_Correctly()
 {
     foreach(BaseStationMessageType messageType in Enum.GetValues(typeof(BaseStationMessageType))) {
         if(messageType == BaseStationMessageType.Unknown) continue;
         string messageTypeText = BaseStationMessageHelper.ConvertToString(messageType);
         string text = String.Format("{0},1,5,2056,7404F2,11267,2008/11/28,23:48:18.611,2008/11/28,23:53:19.161,,,,,,,,,,,,", messageTypeText);
         BaseStationMessage message = _Implementation.Translate(text);
         Assert.AreEqual(messageType, message.MessageType, messageType.ToString());
     }
 }
        private BaseStationMessage CreateBaseStationMessage(Aircraft aircraft, long startVersionExclusive, DateTime now)
        {
            var result = new BaseStationMessage()
            {
                Icao24           = aircraft.Icao24,
                MessageGenerated = now,
                MessageLogged    = now,
                MessageType      = BaseStationMessageType.Transmission,
                TransmissionType = BaseStationTransmissionType.SurfacePosition,
                StatusCode       = BaseStationStatusCode.OK,
            };

            bool versionQualifies <T>(VersionedValue <T> value) => value.Version > startVersionExclusive && value.Value != null;

            if (versionQualifies(aircraft.AltitudeFeet))
            {
                result.Altitude = (int)aircraft.AltitudeFeet;
            }
            if (versionQualifies(aircraft.Callsign))
            {
                result.Callsign = aircraft.Callsign;
            }
            if (versionQualifies(aircraft.GroundSpeedKnots))
            {
                result.GroundSpeed = aircraft.GroundSpeedKnots;
            }
            if (versionQualifies(aircraft.OnGround))
            {
                result.OnGround = aircraft.OnGround;
            }
            if (versionQualifies(aircraft.SpecialPurposeIndicator))
            {
                result.IdentActive = aircraft.SpecialPurposeIndicator;
            }
            if (versionQualifies(aircraft.Squawk))
            {
                result.Squawk = ConvertSquawk(aircraft.Squawk);
            }
            if (versionQualifies(aircraft.Track))
            {
                result.Track = aircraft.Track;
            }
            if (versionQualifies(aircraft.VerticalRateFeetPerSecond))
            {
                result.VerticalRate = (int)aircraft.VerticalRateFeetPerSecond;
            }

            if (versionQualifies(aircraft.Latitude) || versionQualifies(aircraft.Longitude))
            {
                result.Latitude  = aircraft.Latitude;
                result.Longitude = aircraft.Longitude;
            }

            return(result);
        }
Пример #14
0
        public void BaseStationMessage_ToString_Only_Shows_1_Decimal_Place_For_GroundSpeed()
        {
            var message = new BaseStationMessage()
            {
                GroundSpeed = 0.654321F,
            };

            var text = message.ToBaseStationString();

            Assert.AreNotEqual(-1, text.IndexOf(",0.7,"));
        }
Пример #15
0
        public void TestInitialise()
        {
            _OriginalFactory = Factory.TakeSnapshot();

            _Clock = new ClockMock();
            _Timer = TestUtilities.CreateMockImplementation <ITimer>();

            _Compressor = TestUtilities.CreateMockImplementation <IBaseStationMessageCompressor>();

            _Server = Factory.Resolve <IRebroadcastServer>();

            _Feed     = TestUtilities.CreateMockInstance <IFeed>();
            _Listener = TestUtilities.CreateMockInstance <IListener>();
            _Feed.SetupGet(r => r.Listener).Returns(_Listener.Object);

            _Connector = new MockConnector <INetworkConnector, INetworkConnection>();

            _AircraftListJsonBuilder     = TestUtilities.CreateMockImplementation <IAircraftListJsonBuilder>();
            _AircraftListJson            = new AircraftListJson();
            _AircraftListJsonBuilderArgs = null;
            _IgnoreInvisibleFeeds        = null;
            _FallbackToDefault           = null;
            _AircraftListJsonBuilder.Setup(r => r.Build(It.IsAny <AircraftListJsonBuilderArgs>(), It.IsAny <bool>(), It.IsAny <bool>())).Callback((AircraftListJsonBuilderArgs args, bool ignoreInvisibleFeeds, bool fallbackToDefault) => {
                _AircraftListJsonBuilderArgs = args;
                _IgnoreInvisibleFeeds        = ignoreInvisibleFeeds;
                _FallbackToDefault           = fallbackToDefault;
            }).Returns(_AircraftListJson);

            _AircraftList = TestUtilities.CreateMockImplementation <IBaseStationAircraftList>();
            _Feed.SetupGet(r => r.AircraftList).Returns(_AircraftList.Object);
            _SnapshotAircraft = new List <IAircraft>();
            long of1, of2;

            _AircraftList.Setup(m => m.TakeSnapshot(out of1, out of2)).Returns(_SnapshotAircraft);

            _Server.UniqueId  = 1;
            _Server.Name      = "It's the code word";
            _Server.Format    = RebroadcastFormat.Port30003;
            _Server.Feed      = _Feed.Object;
            _Server.Connector = _Connector.Object;

            _ExceptionCaughtEvent              = new EventRecorder <EventArgs <Exception> >();
            _ExceptionCaughtEvent.EventRaised += DefaultExceptionCaughtHandler;
            _OnlineChangedEvent      = new EventRecorder <EventArgs>();
            _Server.ExceptionCaught += _ExceptionCaughtEvent.Handler;
            _Server.OnlineChanged   += _OnlineChangedEvent.Handler;

            _Port30003Message = new BaseStationMessage()
            {
                Icao24 = "313233"
            };
        }
Пример #16
0
        public void BaseStationMessage_ToString_Only_Shows_6_Decimal_Places_For_Latitude_And_Longitude()
        {
            var message = new BaseStationMessage()
            {
                Latitude  = 0.123456789012345,
                Longitude = 0.543210987654321,
            };

            var text = message.ToBaseStationString();

            Assert.AreNotEqual(-1, text.IndexOf(",0.123457,"));
            Assert.AreNotEqual(-1, text.IndexOf(",0.543211,"));
        }
Пример #17
0
        /// <summary>
        /// See interface docs.
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public byte[] Compress(BaseStationMessage message)
        {
            byte[] result = null;

            if (IsMeaningfulMessage(message))
            {
                using (var stream = new MemoryStream()) {
                    using (var writer = new BinaryWriter(stream)) {
                        stream.WriteByte(0);     // <-- reserve a byte for the buffer length
                        writer.Write((ushort)0); // <-- reserve a word for the checksum
                        stream.WriteByte((byte)(int)message.TransmissionType);
                        EncodeIcao(stream, message.Icao24);
                        long optionalFlagsOffset = stream.Position;
                        stream.WriteByte(0); // <-- reserve two bytes for the optional fields flags
                        stream.WriteByte(0); // <--    "
                        OptionalFields optionalFields = OptionalFields.None;
                        if (!String.IsNullOrEmpty(message.Callsign))
                        {
                            optionalFields |= OptionalFields.CallSign; EncodeString(stream, message.Callsign);
                        }
                        if (message.Altitude != null)
                        {
                            optionalFields |= OptionalFields.Altitude; EncodeFloatInt(stream, message.Altitude.Value);
                        }
                        if (message.GroundSpeed != null)
                        {
                            optionalFields |= OptionalFields.GroundSpeed; EncodeFloatShort(writer, message.GroundSpeed.Value);
                        }
                        if (message.Track != null)
                        {
                            optionalFields |= OptionalFields.Track; EncodeFloatShort(writer, message.Track.Value * 10f);
                        }
                        if (message.Latitude != null)
                        {
                            optionalFields |= OptionalFields.Latitude; EncodeFloat(writer, (float)message.Latitude.Value);
                        }
                        if (message.Longitude != null)
                        {
                            optionalFields |= OptionalFields.Longitude; EncodeFloat(writer, (float)message.Longitude.Value);
                        }
                        if (message.VerticalRate != null)
                        {
                            optionalFields |= OptionalFields.VerticalRate; EncodeFloatShort(writer, message.VerticalRate.Value);
                        }
                        if (message.Squawk != null)
                        {
                            optionalFields |= OptionalFields.Squawk; EncodeShort(writer, (short)Math.Max(short.MinValue, Math.Min(short.MaxValue, message.Squawk.Value)));
                        }

                        CompressedFlags flags   = CompressedFlags.None;
                        bool            hasFlag = false;
                        if (message.SquawkHasChanged != null)
                        {
                            optionalFields |= OptionalFields.SquawkHasChanged; hasFlag = true; if (message.SquawkHasChanged.Value)
                            {
                                flags |= CompressedFlags.SquawkHasChanged;
                            }
                        }
                        if (message.Emergency != null)
                        {
                            optionalFields |= OptionalFields.Emergency; hasFlag = true; if (message.Emergency.Value)
                            {
                                flags |= CompressedFlags.Emergency;
                            }
                        }
                        if (message.IdentActive != null)
                        {
                            optionalFields |= OptionalFields.IdentActive; hasFlag = true; if (message.IdentActive.Value)
                            {
                                flags |= CompressedFlags.IdentActive;
                            }
                        }
                        if (message.OnGround != null)
                        {
                            optionalFields |= OptionalFields.OnGround; hasFlag = true; if (message.OnGround.Value)
                            {
                                flags |= CompressedFlags.OnGround;
                            }
                        }
                        if (hasFlag)
                        {
                            stream.WriteByte((byte)flags);
                        }

                        stream.Seek(optionalFlagsOffset, SeekOrigin.Begin);
                        EncodeShort(writer, (short)optionalFields);
                    }

                    result = stream.ToArray();
                    if (result.Length != 0)
                    {
                        result[0] = (byte)result.Length;
                        var checksum = CalculateChecksum(result);
                        result[1] = (byte)(checksum & 0x00ff);
                        result[2] = (byte)((checksum & 0xff00) >> 8);
                    }
                }
            }

            return(result ?? new byte[0]);
        }
Пример #18
0
        /// <summary>
        /// Updates the FirstX / LastX pairs of values of an in-store flight record.
        /// </summary>
        /// <param name="message"></param>
        /// <param name="flight"></param>
        /// <param name="flightRecords"></param>
        /// <param name="isMlat"></param>
        private static void UpdateFirstLastValues(BaseStationMessage message, BaseStationFlight flight, FlightRecords flightRecords, bool isMlat)
        {
            bool isLocationZeroZero = message.Latitude.GetValueOrDefault() == 0F && message.Longitude.GetValueOrDefault() == 0F;

            if (message.Latitude != null && !isLocationZeroZero)
            {
                if (flight.FirstLat == null)
                {
                    flight.FirstLat = message.Latitude;
                }
                flight.LastLat = message.Latitude;
            }
            if (message.Longitude != null && !isLocationZeroZero)
            {
                if (flight.FirstLon == null)
                {
                    flight.FirstLon = message.Longitude;
                }
                flight.LastLon = message.Longitude;
            }
            if (message.Track != null)
            {
                if (flight.FirstTrack == null)
                {
                    flight.FirstTrack = message.Track;
                }
                flight.LastTrack = message.Track;
            }

            if (!isMlat)
            {
                if (message.Altitude != null)
                {
                    if (flight.FirstAltitude == null)
                    {
                        flight.FirstAltitude = message.Altitude;
                    }
                    flight.LastAltitude = message.Altitude;
                }
                if (message.GroundSpeed != null)
                {
                    if (flight.FirstGroundSpeed == null)
                    {
                        flight.FirstGroundSpeed = message.GroundSpeed;
                    }
                    flight.LastGroundSpeed = message.GroundSpeed;
                }
                if (message.OnGround != null)
                {
                    if (flightRecords.OnGround == null)
                    {
                        flightRecords.OnGround = flight.FirstIsOnGround = message.OnGround.Value;
                    }
                    flight.LastIsOnGround = message.OnGround.Value;
                }
                if (message.Squawk != null)
                {
                    if (flight.FirstSquawk == null)
                    {
                        flight.FirstSquawk = message.Squawk;
                    }
                    flight.LastSquawk = message.Squawk;
                }
                if (message.VerticalRate != null)
                {
                    if (flight.FirstVerticalRate == null)
                    {
                        flight.FirstVerticalRate = message.VerticalRate;
                    }
                    flight.LastVerticalRate = message.VerticalRate;
                }
            }
        }
        public void BaseStationMessageCompressor_Compress_And_Decompress_Work_As_Expected()
        {
            ExcelWorksheetData worksheet = new ExcelWorksheetData(TestContext);

            var messageIn = new BaseStationMessage();

            messageIn.MessageType      = worksheet.ParseEnum <BaseStationMessageType>("MessageType");
            messageIn.TransmissionType = worksheet.ParseEnum <BaseStationTransmissionType>("TransmissionType");
            messageIn.StatusCode       = worksheet.ParseEnum <BaseStationStatusCode>("StatusCode");
            messageIn.Icao24           = worksheet.EString("Icao24");
            messageIn.SessionId        = worksheet.Int("SessionId");
            messageIn.AircraftId       = worksheet.Int("AircraftId");
            messageIn.FlightId         = worksheet.Int("FlightId");
            messageIn.MessageGenerated = worksheet.DateTime("MessageGenerated");
            messageIn.MessageLogged    = worksheet.DateTime("MessageLogged");
            messageIn.Callsign         = worksheet.String("Callsign");
            messageIn.Altitude         = worksheet.NInt("Altitude");
            messageIn.GroundSpeed      = worksheet.NInt("GroundSpeed");
            messageIn.Track            = worksheet.NFloat("Track");
            messageIn.Latitude         = worksheet.NDouble("Latitude");
            messageIn.Longitude        = worksheet.NDouble("Longitude");
            messageIn.VerticalRate     = worksheet.NInt("VerticalRate");
            messageIn.Squawk           = worksheet.NInt("Squawk");
            messageIn.SquawkHasChanged = worksheet.NBool("SquawkHasChanged");
            messageIn.Emergency        = worksheet.NBool("Emergency");
            messageIn.IdentActive      = worksheet.NBool("IdentActive");
            messageIn.OnGround         = worksheet.NBool("OnGround");

            int expectedLength = worksheet.Int("Length");

            byte[] bytes = _Compressor.Compress(messageIn);
            Assert.AreEqual(expectedLength, bytes.Length);

            DateTime           earliestDate = DateTime.Now;
            BaseStationMessage messageOut   = _Compressor.Decompress(bytes);
            DateTime           latestDate   = DateTime.Now;

            if (bytes.Length == 0)
            {
                Assert.IsNull(messageOut);
            }
            else
            {
                Assert.AreEqual(messageIn.MessageType, messageOut.MessageType);
                Assert.AreEqual(messageIn.TransmissionType, messageOut.TransmissionType);
                Assert.AreEqual(BaseStationStatusCode.None, messageOut.StatusCode);
                Assert.AreEqual(messageIn.Icao24, messageOut.Icao24);
                Assert.AreEqual(0, messageOut.SessionId);
                Assert.AreEqual(0, messageOut.AircraftId);
                Assert.AreEqual(0, messageOut.FlightId);
                Assert.AreEqual((double)earliestDate.Ticks, (double)messageOut.MessageGenerated.Ticks, (double)latestDate.Ticks - (double)earliestDate.Ticks);
                Assert.AreEqual((double)earliestDate.Ticks, (double)messageOut.MessageLogged.Ticks, (double)latestDate.Ticks - (double)earliestDate.Ticks);
                Assert.AreEqual(messageIn.Callsign, messageOut.Callsign);
                Assert.AreEqual(messageIn.Altitude, messageOut.Altitude);
                Assert.AreEqual(messageIn.GroundSpeed, messageOut.GroundSpeed);
                Assert.AreEqual(messageIn.Track, messageOut.Track);
                if (messageIn.Latitude == null)
                {
                    Assert.IsNull(messageOut.Latitude);
                }
                else
                {
                    Assert.AreEqual(messageIn.Latitude.Value, messageOut.Latitude.Value, 0.000001);
                }
                if (messageIn.Longitude == null)
                {
                    Assert.IsNull(messageOut.Longitude);
                }
                else
                {
                    Assert.AreEqual(messageIn.Longitude.Value, messageOut.Longitude.Value, 0.000001);
                }
                Assert.AreEqual(messageIn.VerticalRate, messageOut.VerticalRate);
                Assert.AreEqual(messageIn.Squawk, messageOut.Squawk);
                Assert.AreEqual(messageIn.SquawkHasChanged, messageOut.SquawkHasChanged);
                Assert.AreEqual(messageIn.Emergency, messageOut.Emergency);
                Assert.AreEqual(messageIn.IdentActive, messageOut.IdentActive);
                Assert.AreEqual(messageIn.OnGround, messageOut.OnGround);
            }
        }
Пример #20
0
        /// <summary>
        /// Creates database records and updates internal objects to track an aircraft that is currently transmitting messages.
        /// </summary>
        /// <param name="message"></param>
        /// <param name="isMlat"></param>
        /// <remarks>
        /// This defers the recording of the flight for as long as possible so that if the database is locked then we don't
        /// have a record of the flight, and the next message will try again to record the flight.
        /// </remarks>
        private void TrackFlight(BaseStationMessage message, bool isMlat)
        {
            if (IsTransmissionMessage(message))
            {
                lock (_SyncLock) {
                    if (_Session != null)
                    {
                        var localNow = Provider.LocalNow;
                        var icao24   = CustomConvert.Icao24(message.Icao24);
                        if (icao24 > 0)
                        {
                            FlightRecords flightRecords;
                            if (!_FlightMap.TryGetValue(icao24, out flightRecords))
                            {
                                flightRecords = new FlightRecords()
                                {
                                    Aircraft = new BaseStationAircraft()
                                    {
                                        ModeS        = message.Icao24,
                                        FirstCreated = localNow,
                                    },
                                    Flight = new BaseStationFlight()
                                    {
                                        Callsign            = message.Callsign,
                                        StartTime           = localNow,
                                        NumADSBMsgRec       = 0,
                                        NumAirCallRepMsgRec = 0,
                                        NumAirPosMsgRec     = 0,
                                        NumAirToAirMsgRec   = 0,
                                        NumAirVelMsgRec     = 0,
                                        NumIDMsgRec         = 0,
                                        NumModeSMsgRec      = 0,
                                        NumPosMsgRec        = 0,
                                        NumSurAltMsgRec     = 0,
                                        NumSurIDMsgRec      = 0,
                                        NumSurPosMsgRec     = 0,
                                    },
                                };

                                _FlightMap.Add(icao24, flightRecords);
                            }

                            var flight = flightRecords.Flight;
                            flightRecords.EndTimeUtc = Provider.UtcNow;
                            flight.EndTime           = localNow;
                            if (!isMlat)
                            {
                                if (message.SquawkHasChanged.GetValueOrDefault())
                                {
                                    flight.HadAlert = true;
                                }
                                if (message.IdentActive.GetValueOrDefault())
                                {
                                    flight.HadSpi = true;
                                }
                                if (message.Squawk == 7500 || message.Squawk == 7600 || message.Squawk == 7700)
                                {
                                    flight.HadEmergency = true;
                                }
                            }
                            UpdateFirstLastValues(message, flight, flightRecords, isMlat);
                            UpdateMessageCounters(message, flight);

                            if (!String.IsNullOrEmpty(message.Callsign))
                            {
                                if (message.Callsign != flightRecords.Flight.Callsign)
                                {
                                    flightRecords.Flight.Callsign = message.Callsign;
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #21
0
 /// <summary>
 /// Returns true if the message holds values transmitted from a vehicle.
 /// </summary>
 /// <param name="message"></param>
 /// <returns></returns>
 private bool IsTransmissionMessage(BaseStationMessage message)
 {
     return(!String.IsNullOrEmpty(message.Icao24) &&
            message.MessageType == BaseStationMessageType.Transmission &&
            message.TransmissionType != BaseStationTransmissionType.None);
 }
        /// <summary>
        /// See interface docs.
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        public IEnumerable <BaseStationMessageEventArgs> ConvertIntoBaseStationMessageEventArgs(AirnavXRangeJson json)
        {
            var result = new List <BaseStationMessageEventArgs>();

            foreach (var jsonAircraft in json.Aircraft)
            {
                var message = new BaseStationMessage()
                {
                    MessageType      = BaseStationMessageType.Transmission,
                    TransmissionType = BaseStationTransmissionType.AirToAir,        // This needs to be something other than "None" or "AllCallReply" if we want to have these messages work with the message compressor
                    StatusCode       = BaseStationStatusCode.None,
                };

                if (jsonAircraft.SignalLevel != null)
                {
                    message.SignalLevel = (int)(jsonAircraft.SignalLevel + -0.5);
                }
                if (jsonAircraft.Icao24 != null)
                {
                    message.Icao24 = jsonAircraft.Icao24;
                }
                if (jsonAircraft.Altitude != null)
                {
                    message.Altitude = jsonAircraft.Altitude;
                }
                if (jsonAircraft.Callsign != null)
                {
                    message.Callsign = jsonAircraft.Callsign;
                }
                if (jsonAircraft.GroundSpeed != null)
                {
                    message.GroundSpeed = jsonAircraft.GroundSpeed;
                }
                if (jsonAircraft.Track != null)
                {
                    message.Track = jsonAircraft.Track;
                }
                if (jsonAircraft.Squawk != null)
                {
                    message.Squawk = jsonAircraft.Squawk;
                }
                if (jsonAircraft.VerticalRate != null)
                {
                    message.VerticalRate = jsonAircraft.VerticalRate;
                }
                if (jsonAircraft.OnGround != null)
                {
                    message.OnGround = jsonAircraft.OnGround;
                }

                if (jsonAircraft.Latitude != null || jsonAircraft.Longitude != null)
                {
                    if (jsonAircraft.Latitude != null)
                    {
                        message.Latitude = jsonAircraft.Latitude;
                    }
                    if (jsonAircraft.Longitude != null)
                    {
                        message.Longitude = jsonAircraft.Longitude;
                    }
                }

                result.Add(new BaseStationMessageEventArgs(message));
            }

            return(result);
        }
        /// <summary>
        /// See interface docs.
        /// </summary>
        /// <param name="text"></param>
        /// <param name="signalLevel"></param>
        /// <returns></returns>
        public BaseStationMessage Translate(string text, int?signalLevel)
        {
            var result = new BaseStationMessage()
            {
                SignalLevel = signalLevel
            };

            if (!String.IsNullOrEmpty(text))
            {
                var      isMlat = false;
                string[] parts  = text.Split(',');
                for (int c = 0; c < parts.Length; c++)
                {
                    string chunk = parts[c];
                    try {
                        if (!String.IsNullOrEmpty(chunk))
                        {
                            switch (c)
                            {
                            case 0:     result.MessageType = BaseStationMessageHelper.ConvertToBaseStationMessageType(chunk, ref isMlat); break;

                            case 1:     result.TransmissionType = result.MessageType == BaseStationMessageType.Transmission ? BaseStationMessageHelper.ConvertToBaseStationTransmissionType(chunk) : BaseStationTransmissionType.None; break;

                            case 2:     result.SessionId = ParseInt(chunk); break;

                            case 3:     result.AircraftId = ParseInt(chunk); break;

                            case 4:     result.Icao24 = chunk == null ? null : chunk.ToUpperInvariant(); break;

                            case 5:     result.FlightId = ParseInt(chunk); break;

                            case 6:     result.MessageGenerated = ParseDate(chunk); break;

                            case 7:     result.MessageGenerated = ParseTime(result.MessageGenerated, chunk); break;

                            case 8:     result.MessageLogged = ParseDate(chunk); break;

                            case 9:     result.MessageLogged = ParseTime(result.MessageLogged, chunk); break;

                            case 10:    if (result.MessageType == BaseStationMessageType.StatusChange)
                                {
                                    result.StatusCode = BaseStationMessageHelper.ConvertToBaseStationStatusCode(chunk);
                                }
                                else
                                {
                                    result.Callsign = chunk.Replace("@", "").Trim();
                                } break;

                            case 11:    result.Altitude = ParseInt(chunk); break;

                            case 12:    result.GroundSpeed = ParseFloat(chunk); break;

                            case 13:    result.Track = ParseFloat(chunk); break;

                            case 14:    result.Latitude = ParseDouble(chunk); break;

                            case 15:    result.Longitude = ParseDouble(chunk); break;

                            case 16:    result.VerticalRate = ParseInt(chunk); break;

                            case 17:    result.Squawk = ParseInt(chunk); if (result.Squawk == 0)
                                {
                                    result.Squawk = null;
                                }
                                break;

                            case 18:    result.SquawkHasChanged = ParseBool(chunk); break;

                            case 19:    result.Emergency = ParseBool(chunk); break;

                            case 20:    result.IdentActive = ParseBool(chunk); break;

                            case 21:    result.OnGround = ParseBool(chunk); break;
                            }
                        }
                    } catch (Exception ex) {
                        Debug.WriteLine(String.Format("BaseStationMessageTranslator.Translate caught exception: {0}", ex.ToString()));

                        // I would prefer to pass ex as the inner exception to this. However Microsoft's Application.ThreadException unhandled exception handler
                        // strips off all outer exceptions and only shows the bottom-most exception - i.e., in our case, the exception from a Parse method. This
                        // is not useful in isolation, we need to know what was being translated, the context in which the exception was thrown. So I have ended
                        // up with this, which is not very nice but shows enough information in the unhandled exception handler to allow diagnosis of the problem.
                        throw new BaseStationTranslatorException($"{ex.Message} while translating \"{chunk}\" (chunk {c}) in \"{text}\"");
                    }
                }

                result.IsMlat = isMlat;
            }

            return(result);
        }
        public void BaseStationMessageTranslator_Translate_Parses_Unknown_Message_Type_Correctly()
        {
            BaseStationMessage message = _Implementation.Translate("NEW2ME,1,5,2056,7404F2,11267,2008/11/28,23:48:18.611,2008/11/28,23:53:19.161,,,,,,,,,,,,", 123);

            Assert.AreEqual(BaseStationMessageType.Unknown, message.MessageType);
        }
Пример #25
0
        /// <summary>
        /// See interface docs.
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public BaseStationMessage Decompress(byte[] buffer)
        {
            BaseStationMessage result = null;

            if (buffer.Length > 0 && (int)buffer[0] == buffer.Length)
            {
                using (var stream = new MemoryStream(buffer)) {
                    using (var reader = new BinaryReader(stream)) {
                        result = new BaseStationMessage();
                        stream.ReadByte();                     // <-- length of buffer, we can skip this

                        ushort checksum = reader.ReadUInt16(); // the checksum is skipped as well - caller should ensure it's a valid message before decompression

                        result.MessageType      = BaseStationMessageType.Transmission;
                        result.StatusCode       = BaseStationStatusCode.None;
                        result.TransmissionType = (BaseStationTransmissionType)stream.ReadByte();
                        result.Icao24           = DecodeIcao(stream);
                        result.MessageGenerated = result.MessageLogged = DateTime.Now;

                        OptionalFields optionalFields = (OptionalFields)DecodeShort(reader);

                        if ((optionalFields & OptionalFields.CallSign) != 0)
                        {
                            result.Callsign = DecodeString(stream);
                        }
                        if ((optionalFields & OptionalFields.Altitude) != 0)
                        {
                            result.Altitude = (int)DecodeFloatInt(stream);
                        }
                        if ((optionalFields & OptionalFields.GroundSpeed) != 0)
                        {
                            result.GroundSpeed = (int)DecodeFloatShort(reader);
                        }
                        if ((optionalFields & OptionalFields.Track) != 0)
                        {
                            result.Track = DecodeFloatShort(reader) / 10f;
                        }
                        if ((optionalFields & OptionalFields.Latitude) != 0)
                        {
                            result.Latitude = DecodeFloat(reader);
                        }
                        if ((optionalFields & OptionalFields.Longitude) != 0)
                        {
                            result.Longitude = DecodeFloat(reader);
                        }
                        if ((optionalFields & OptionalFields.VerticalRate) != 0)
                        {
                            result.VerticalRate = (int)DecodeFloatShort(reader);
                        }
                        if ((optionalFields & OptionalFields.Squawk) != 0)
                        {
                            result.Squawk = DecodeShort(reader);
                        }

                        bool hasSquawkHasChanged = (optionalFields & OptionalFields.SquawkHasChanged) != 0;
                        bool hasEmergency        = (optionalFields & OptionalFields.Emergency) != 0;
                        bool hasIdentActive      = (optionalFields & OptionalFields.IdentActive) != 0;
                        bool hasOnGround         = (optionalFields & OptionalFields.OnGround) != 0;

                        if (hasSquawkHasChanged || hasEmergency || hasIdentActive || hasOnGround)
                        {
                            CompressedFlags flags = (CompressedFlags)stream.ReadByte();
                            if (hasSquawkHasChanged)
                            {
                                result.SquawkHasChanged = (flags & CompressedFlags.SquawkHasChanged) != 0;
                            }
                            if (hasEmergency)
                            {
                                result.Emergency = (flags & CompressedFlags.Emergency) != 0;
                            }
                            if (hasIdentActive)
                            {
                                result.IdentActive = (flags & CompressedFlags.IdentActive) != 0;
                            }
                            if (hasOnGround)
                            {
                                result.OnGround = (flags & CompressedFlags.OnGround) != 0;
                            }
                        }
                    }
                }
            }

            return(result);
        }
        public void BaseStationMessageTranslator_Translate_Converts_Zero_Squawks_To_Null()
        {
            BaseStationMessage message = _Implementation.Translate("MSG,1,5,2056,7404F2,11267,2008/11/28,23:48:18.611,2008/11/28,23:53:19.161,ABC,,,,,,,0,,,,", 123);

            Assert.AreEqual(null, message.Squawk);
        }
        public void BaseStationMessageTranslator_Translate_Strips_At_Signs_In_Callsign()
        {
            BaseStationMessage message = _Implementation.Translate("MSG,1,5,2056,7404F2,11267,2008/11/28,23:48:18.611,2008/11/28,23:53:19.161,A@B,,,,,,,,,,,", 123);

            Assert.AreEqual("AB", message.Callsign);
        }
        /// <summary>
        /// See interface docs.
        /// </summary>
        /// <param name="aircraftListJson"></param>
        /// <returns></returns>
        public IEnumerable <BaseStationMessageEventArgs> ConvertIntoBaseStationMessageEventArgs(AircraftListJson aircraftListJson)
        {
            var result = new List <BaseStationMessageEventArgs>();

            foreach (var json in aircraftListJson.Aircraft)
            {
                var message = new BaseStationMessage()
                {
                    MessageType      = BaseStationMessageType.Transmission,
                    TransmissionType = BaseStationTransmissionType.AirToAir,        // This needs to be something other than "None" or "AllCallReply" if we want to have these messages work with the message compressor
                    StatusCode       = BaseStationStatusCode.None,
                };

                if (json.Callsign != null)
                {
                    message.Callsign = json.Callsign;
                }
                if (json.Emergency != null)
                {
                    message.Emergency = json.Emergency;
                }
                if (json.GroundSpeed != null)
                {
                    message.GroundSpeed = json.GroundSpeed;
                }
                if (json.Icao24 != null)
                {
                    message.Icao24 = json.Icao24;
                }
                if (json.OnGround != null)
                {
                    message.OnGround = json.OnGround;
                }
                if (json.SignalLevel != null)
                {
                    message.SignalLevel = json.SignalLevel;
                }
                if (json.Track != null)
                {
                    message.Track = json.Track;
                }
                if (json.VerticalRate != null)
                {
                    message.VerticalRate = json.VerticalRate;
                }

                if (json.Latitude != null || json.Longitude != null)
                {
                    if (json.Latitude != null)
                    {
                        message.Latitude = json.Latitude;
                    }
                    if (json.Longitude != null)
                    {
                        message.Longitude = json.Longitude;
                    }
                    if (json.PositionIsMlat != null)
                    {
                        message.IsMlat = json.PositionIsMlat.Value;
                    }
                }

                if (json.Squawk != null)
                {
                    int squawk;
                    if (int.TryParse(json.Squawk, out squawk))
                    {
                        message.Squawk = squawk;
                    }
                }

                if (json.AltitudeType != null)
                {
                    AddSupplementaryValue(message, r => r.AltitudeIsGeometric = json.AltitudeType == 1);
                }
                if (json.CallsignIsSuspect != null)
                {
                    AddSupplementaryValue(message, r => r.CallsignIsSuspect = json.CallsignIsSuspect);
                }
                if (json.SpeedType != null)
                {
                    AddSupplementaryValue(message, r => r.SpeedType = (SpeedType)json.SpeedType);
                }
                if (json.TargetAltitude != null)
                {
                    AddSupplementaryValue(message, r => r.TargetAltitude = json.TargetAltitude);
                }
                if (json.TargetTrack != null)
                {
                    AddSupplementaryValue(message, r => r.TargetHeading = json.TargetTrack);
                }
                if (json.TrackIsHeading != null)
                {
                    AddSupplementaryValue(message, r => r.TrackIsHeading = json.TrackIsHeading);
                }
                if (json.TransponderType != null)
                {
                    AddSupplementaryValue(message, r => r.TransponderType = (TransponderType)json.TransponderType);
                }
                if (json.VerticalRateType != null)
                {
                    AddSupplementaryValue(message, r => r.VerticalRateIsGeometric = json.VerticalRateType == 1);
                }
                if (json.AirPressureInHg != null)
                {
                    AddSupplementaryValue(message, r => r.PressureSettingMb = AirPressure.InHgToMillibars(json.AirPressureInHg));
                }

                if (json.Altitude != null)
                {
                    // When pressure altitude calculations were introduced the sending side was modified to
                    // send Altitude, GeometricAltitude and AltitudeType as a set. However, before that was
                    // introduced they'd only be sent if they changed.
                    if (json.GeometricAltitude == null || json.AltitudeType == null)
                    {
                        message.Altitude = json.Altitude;
                    }
                    else
                    {
                        switch (json.AltitudeType)
                        {
                        case (int)AltitudeType.Barometric:
                            message.Altitude = json.Altitude;
                            break;

                        case (int)AltitudeType.Geometric:
                            message.Altitude = json.GeometricAltitude;
                            break;

                        default:
                            throw new NotImplementedException();
                        }
                    }
                }

                var eventArgs = new BaseStationMessageEventArgs(message, isOutOfBand: false, isSatcomFeed: json.IsSatcomFeed);
                result.Add(eventArgs);
            }

            return(result);
        }
Пример #29
0
 public void TestInitialise()
 {
     _Implementation = new BaseStationMessage();
 }
Пример #30
0
 /// <summary>
 /// Converts the message passed across to the bytes that are expected to be transmitted for it.
 /// </summary>
 /// <param name="message"></param>
 /// <returns></returns>
 private byte[] ExpectedBytes(BaseStationMessage message)
 {
     return(Encoding.ASCII.GetBytes(String.Concat(message.ToBaseStationString(), "\r\n")));
 }