public void TestInitialise() { _Compressor = Factory.Singleton.Resolve<IBaseStationMessageCompressor>(); _Message = new BaseStationMessage(); _Message.MessageType = BaseStationMessageType.Transmission; _Message.TransmissionType = BaseStationTransmissionType.SurveillanceAlt; _Message.Icao24 = "405012"; }
/// <summary> /// See interface docs. /// </summary> /// <param name="text"></param> /// <returns></returns> public BaseStationMessage Translate(string text) { var result = new BaseStationMessage(); if(!String.IsNullOrEmpty(text)) { 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); 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; 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(String.Format("{0} while translating \"{1}\" (chunk {2}) in \"{3}\"", ex.Message, chunk, c, text)); } } } return result; }
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" }; }
/// <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; }
/// <summary> /// Creates a new object. /// </summary> /// <param name="message"></param> public BaseStationMessageEventArgs(BaseStationMessage message) { Message = message; }
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; }
public void Plugin_Flight_Does_Record_Latitude_Of_NonZero_Longitude_Of_Zero() { SetEnabledOption(true); var startTime = SetProviderTimes(new DateTime(2012, 3, 4, 5, 6, 7)); _Plugin.Startup(_StartupParameters); BaseStationFlight flight = null; _BaseStationDatabase.Setup(d => d.UpdateFlight(It.IsAny<BaseStationFlight>())).Callback((BaseStationFlight f) => { flight = f; }); var message = new BaseStationMessage() { AircraftId = 99, Icao24 = "X", FlightId = 429, SessionId = 1239, Callsign = "ABC123", Altitude = 31, Emergency = true, GroundSpeed = 289, IdentActive = true, Latitude = 0.1F, Longitude = 0F, MessageGenerated = DateTime.Now, MessageLogged = DateTime.Now, MessageNumber = 12389, MessageType = BaseStationMessageType.Transmission, OnGround = true, Squawk = 1293, SquawkHasChanged = true, StatusCode = BaseStationStatusCode.None, Track = 12.4F, TransmissionType = BaseStationTransmissionType.AirToAir, VerticalRate = 18 }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); SetProviderTimes(startTime.AddMinutes(MinutesBeforeFlightClosed)); _HeartbeatService.Raise(h => h.SlowTick += null, EventArgs.Empty); Assert.AreEqual(0.1F, flight.FirstLat); Assert.AreEqual(0F, flight.FirstLon); Assert.AreEqual(0.1F, flight.LastLat); Assert.AreEqual(0F, flight.LastLon); }
public void Plugin_Flight_Updates_Message_Counters_Correctly() { // These are the nullable integers which start with "Num" var worksheet = new ExcelWorksheetData(TestContext); SetEnabledOption(true); BaseStationFlight flight = null; _BaseStationDatabase.Setup(d => d.UpdateFlight(It.IsAny<BaseStationFlight>())).Callback((BaseStationFlight f) => { flight = f; }); _Plugin.Startup(_StartupParameters); var message = new BaseStationMessage() { Icao24 = "Z", MessageType = worksheet.ParseEnum<BaseStationMessageType>("MessageType"), TransmissionType = worksheet.ParseEnum<BaseStationTransmissionType>("TransmissionType"), StatusCode = worksheet.ParseEnum<BaseStationStatusCode>("StatusCode"), GroundSpeed = worksheet.NFloat("GroundSpeed"), Track = worksheet.NFloat("Track"), Latitude = worksheet.NFloat("Latitude"), Longitude = worksheet.NFloat("Longitude"), VerticalRate = worksheet.NInt("VerticalRate"), }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); SetProviderTimes(_Provider.Object.LocalNow.AddMinutes(MinutesBeforeFlightClosed)); _HeartbeatService.Raise(s => s.SlowTick += null, EventArgs.Empty); _BaseStationDatabase.Verify(d => d.UpdateFlight(It.IsAny<BaseStationFlight>()), Times.Once()); // Note that the totals are not null after the final update even if no messages were received in a particular category Assert.AreEqual(worksheet.Int("NumPosMsgRec"), flight.NumPosMsgRec.Value); Assert.AreEqual(worksheet.Int("NumADSBMsgRec"), flight.NumADSBMsgRec.Value); Assert.AreEqual(worksheet.Int("NumModeSMsgRec"), flight.NumModeSMsgRec.Value); Assert.AreEqual(worksheet.Int("NumIDMsgRec"), flight.NumIDMsgRec.Value); Assert.AreEqual(worksheet.Int("NumSurPosMsgRec"), flight.NumSurPosMsgRec.Value); Assert.AreEqual(worksheet.Int("NumAirPosMsgRec"), flight.NumAirPosMsgRec.Value); Assert.AreEqual(worksheet.Int("NumAirVelMsgRec"), flight.NumAirVelMsgRec.Value); Assert.AreEqual(worksheet.Int("NumSurAltMsgRec"), flight.NumSurAltMsgRec.Value); Assert.AreEqual(worksheet.Int("NumSurIDMsgRec"), flight.NumSurIDMsgRec.Value); Assert.AreEqual(worksheet.Int("NumAirToAirMsgRec"), flight.NumAirToAirMsgRec.Value); Assert.AreEqual(worksheet.Int("NumAirCallRepMsgRec"), flight.NumAirCallRepMsgRec.Value); }
public void Plugin_Flight_EndTime_Reflects_Time_Of_Last_Message_From_Aircraft() { SetEnabledOption(true); _Plugin.Startup(_StartupParameters); var startTime = SetProviderTimes(new DateTime(2012, 3, 4, 5, 6, 7)); var message = new BaseStationMessage() { Icao24 = "123456", MessageType = BaseStationMessageType.Transmission, TransmissionType = BaseStationTransmissionType.AirToAir }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); SetProviderTimes(startTime.AddMinutes(1)); _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); var endTime = SetProviderTimes(startTime.AddMinutes(7)); _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); _BaseStationDatabase.Setup(d => d.UpdateFlight(It.IsAny<BaseStationFlight>())).Callback((BaseStationFlight flight) => { Assert.AreEqual(startTime, flight.StartTime); Assert.AreEqual(endTime, flight.EndTime); }); SetProviderTimes(startTime.AddMinutes(MinutesBeforeFlightClosed)); _HeartbeatService.Raise(s => s.SlowTick += null, EventArgs.Empty); _BaseStationDatabase.Verify(d => d.UpdateFlight(It.IsAny<BaseStationFlight>()), Times.Never()); SetProviderTimes(endTime.AddMinutes(MinutesBeforeFlightClosed).AddMilliseconds(-1)); _HeartbeatService.Raise(s => s.SlowTick += null, EventArgs.Empty); _BaseStationDatabase.Verify(d => d.UpdateFlight(It.IsAny<BaseStationFlight>()), Times.Never()); SetProviderTimes(endTime.AddMinutes(MinutesBeforeFlightClosed)); _HeartbeatService.Raise(s => s.SlowTick += null, EventArgs.Empty); _BaseStationDatabase.Verify(d => d.UpdateFlight(It.IsAny<BaseStationFlight>()), Times.Once()); }
public void Plugin_Reports_Exceptions_During_Flight_Update() { var exception = new InvalidOperationException(); SetEnabledOption(true); _BaseStationDatabase.Setup(d => d.UpdateFlight(It.IsAny<BaseStationFlight>())).Callback(() => { throw exception; }); var startTime = SetProviderTimes(DateTime.Now); _Plugin.Startup(_StartupParameters); _Plugin.StatusChanged += _StatusChangedEvent.Handler; _StatusChangedEvent.EventRaised += (s, a) => { Assert.AreEqual(String.Format("Exception caught: {0}", exception.Message), _Plugin.StatusDescription); }; var message = new BaseStationMessage() { AircraftId = 99, Icao24 = "X", MessageType = BaseStationMessageType.Transmission, TransmissionType = BaseStationTransmissionType.AirToAir }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); var endTime = SetProviderTimes(startTime.AddMinutes(MinutesBeforeFlightClosed)); _HeartbeatService.Raise(s => s.SlowTick += null, EventArgs.Empty); Assert.AreEqual(1, _StatusChangedEvent.CallCount); Assert.AreSame(_Plugin, _StatusChangedEvent.Sender); _Log.Verify(g => g.WriteLine(It.IsAny<string>(), exception.ToString()), Times.Once()); }
public void Plugin_Aircraft_Database_Not_Repeatedly_Polled_For_Same_Aircraft() { SetEnabledOption(true); BaseStationAircraft aircraft = new BaseStationAircraft(); _BaseStationDatabase.Setup(d => d.GetAircraftByCode("X")).Returns(aircraft); _Plugin.Startup(_StartupParameters); var messageX = new BaseStationMessage() { AircraftId = 99, Icao24 = "X", MessageType = BaseStationMessageType.Transmission, TransmissionType = BaseStationTransmissionType.AirToAir }; var messageY = new BaseStationMessage() { AircraftId = 42, Icao24 = "Y", MessageType = BaseStationMessageType.Transmission, TransmissionType = BaseStationTransmissionType.AirToAir }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(messageX)); _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(messageX)); _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(messageY)); _BaseStationDatabase.Verify(d => d.GetAircraftByCode("X"), Times.Once()); _BaseStationDatabase.Verify(d => d.GetAircraftByCode("Y"), Times.Once()); }
public void Plugin_Flight_Record_Still_Inserted_If_Aircraft_Record_Already_Exists_For_Transmitting_Aircraft() { SetEnabledOption(true); BaseStationFlight flight = null; BaseStationAircraft aircraft = new BaseStationAircraft() { AircraftID = 5832, ModeS = "X" }; _BaseStationDatabase.Setup(d => d.GetAircraftByCode("X")).Returns(aircraft); _BaseStationDatabase.Setup(d => d.InsertFlight(It.IsAny<BaseStationFlight>())).Callback((BaseStationFlight f) => { flight = f; }); _Plugin.Startup(_StartupParameters); var message = new BaseStationMessage() { AircraftId = 99, Icao24 = "X", MessageType = BaseStationMessageType.Transmission, TransmissionType = BaseStationTransmissionType.AirToAir }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); _BaseStationDatabase.Verify(d => d.InsertFlight(It.IsAny<BaseStationFlight>()), Times.Once()); Assert.AreEqual(5832, flight.AircraftID); }
public void Plugin_Aircraft_Record_Not_Touched_If_Aircraft_Record_Already_Exists_For_Transmitting_Aircraft() { SetEnabledOption(true); BaseStationAircraft aircraft = new BaseStationAircraft(); _BaseStationDatabase.Setup(d => d.GetAircraftByCode("X")).Returns(aircraft); _Plugin.Startup(_StartupParameters); var message = new BaseStationMessage() { AircraftId = 99, Icao24 = "X" }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); _BaseStationDatabase.Verify(d => d.InsertAircraft(It.IsAny<BaseStationAircraft>()), Times.Never()); _BaseStationDatabase.Verify(d => d.UpdateAircraft(It.IsAny<BaseStationAircraft>()), Times.Never()); }
public void Plugin_Only_Takes_Notice_Of_Transmission_Messages() { SetEnabledOption(true); _Plugin.Startup(_StartupParameters); int expectedInserts = 0; int counter = 0; var messageTypes = from m in Enum.GetValues(typeof(BaseStationMessageType)).OfType<BaseStationMessageType>() from t in Enum.GetValues(typeof(BaseStationTransmissionType)).OfType<BaseStationTransmissionType>() from s in Enum.GetValues(typeof(BaseStationStatusCode)).OfType<BaseStationStatusCode>() select new { MessageType = m, TransmissionType = t, StatusCode = s }; foreach(var messageType in messageTypes) { var message = new BaseStationMessage() { MessageType = messageType.MessageType, TransmissionType = messageType.TransmissionType, StatusCode = messageType.StatusCode, Icao24 = counter++.ToString(), }; if(message.MessageType == BaseStationMessageType.Transmission && message.TransmissionType != BaseStationTransmissionType.None) ++expectedInserts; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); _BaseStationDatabase.Verify(d => d.InsertFlight(It.IsAny<BaseStationFlight>()), Times.Exactly(expectedInserts), messageType.ToString()); } }
public void Plugin_Flight_Record_Written_When_First_Message_From_Aircraft_Received() { SetEnabledOption(true); _BaseStationDatabase.Setup(d => d.InsertFlight(It.IsAny<BaseStationFlight>())).Callback((BaseStationFlight flight) => { Assert.AreEqual(0, flight.FlightID); Assert.AreEqual(5483, flight.AircraftID); Assert.AreEqual(42, flight.SessionID); Assert.AreEqual(null, flight.Aircraft); Assert.AreEqual("ABC123", flight.Callsign); Assert.AreEqual(_Provider.Object.LocalNow, flight.StartTime); Assert.AreEqual(null, flight.EndTime); Assert.AreEqual(null, flight.FirstAltitude); Assert.AreEqual(null, flight.FirstGroundSpeed); Assert.AreEqual(false, flight.FirstIsOnGround); Assert.AreEqual(null, flight.FirstLat); Assert.AreEqual(null, flight.FirstLon); Assert.AreEqual(null, flight.FirstSquawk); Assert.AreEqual(null, flight.FirstTrack); Assert.AreEqual(null, flight.FirstVerticalRate); Assert.AreEqual(false, flight.HadAlert); Assert.AreEqual(false, flight.HadEmergency); Assert.AreEqual(false, flight.HadSpi); Assert.AreEqual(null, flight.LastAltitude); Assert.AreEqual(null, flight.LastGroundSpeed); Assert.AreEqual(false, flight.LastIsOnGround); Assert.AreEqual(null, flight.LastLat); Assert.AreEqual(null, flight.LastLon); Assert.AreEqual(null, flight.LastSquawk); Assert.AreEqual(null, flight.LastTrack); Assert.AreEqual(null, flight.LastVerticalRate); Assert.AreEqual(null, flight.NumADSBMsgRec); Assert.AreEqual(null, flight.NumModeSMsgRec); Assert.AreEqual(null, flight.NumSurPosMsgRec); Assert.AreEqual(null, flight.NumAirPosMsgRec); Assert.AreEqual(null, flight.NumAirVelMsgRec); Assert.AreEqual(null, flight.NumSurAltMsgRec); Assert.AreEqual(null, flight.NumSurIDMsgRec); Assert.AreEqual(null, flight.NumAirToAirMsgRec); Assert.AreEqual(null, flight.NumAirCallRepMsgRec); Assert.AreEqual(null, flight.NumPosMsgRec); }); _BaseStationDatabase.Setup(d => d.GetAircraftByCode("X")).Returns((BaseStationAircraft)null); _BaseStationDatabase.Setup(d => d.InsertSession(It.IsAny<BaseStationSession>())).Callback((BaseStationSession s) => { s.SessionID = 42; }); _BaseStationDatabase.Setup(d => d.InsertAircraft(It.IsAny<BaseStationAircraft>())).Callback((BaseStationAircraft a) => { a.AircraftID = 5483; }); _Plugin.Startup(_StartupParameters); var message = new BaseStationMessage() { AircraftId = 99, Icao24 = "X", FlightId = 429, SessionId = 1239, Callsign = "ABC123", Altitude = 31, Emergency = true, GroundSpeed = 289, IdentActive = true, Latitude = 31.1F, Longitude = 123.1F, MessageGenerated = DateTime.Now, MessageLogged = DateTime.Now, MessageNumber = 12389, MessageType = BaseStationMessageType.Transmission, OnGround = true, Squawk = 1293, SquawkHasChanged = true, StatusCode = BaseStationStatusCode.None, Track = 12.4F, TransmissionType = BaseStationTransmissionType.AirToAir, VerticalRate = 18 }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); _BaseStationDatabase.Verify(d => d.InsertFlight(It.IsAny<BaseStationFlight>()), Times.Once()); }
/// <summary> /// Creates a new object. /// </summary> /// <param name="message"></param> /// <param name="isOutOfBand"></param> /// <param name="isSatcomFeed"></param> public BaseStationMessageEventArgs(BaseStationMessage message, bool isOutOfBand, bool isSatcomFeed) : this(message) { IsOutOfBand = isOutOfBand; IsSatcomFeed = isSatcomFeed; }
public void Plugin_Flight_Updated_Correctly_When_Transmissions_Received_After_Clocks_Go_Forwards_During_Flight() { SetEnabledOption(true); // First message is received when both local and UTC are the same value var startTime = SetProviderTimes(new DateTime(2012, 3, 4, 5, 6, 7)); BaseStationFlight flight = null; _BaseStationDatabase.Setup(d => d.UpdateFlight(It.IsAny<BaseStationFlight>())).Callback((BaseStationFlight f) => { flight = f; }); _Plugin.Startup(_StartupParameters); var message = new BaseStationMessage() { AircraftId = 99, Icao24 = "X", FlightId = 429, SessionId = 1239, Callsign = "ABC123", Altitude = 31, Emergency = true, GroundSpeed = 289, IdentActive = true, Latitude = 31.1F, Longitude = 123.1F, MessageGenerated = DateTime.Now, MessageLogged = DateTime.Now, MessageNumber = 12389, MessageType = BaseStationMessageType.Transmission, OnGround = true, Squawk = 1293, SquawkHasChanged = true, StatusCode = BaseStationStatusCode.None, Track = 12.4F, TransmissionType = BaseStationTransmissionType.AirToAir, VerticalRate = 18 }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); // Next two messages come in after one minute each, but after local time is one hour ahead of UTC. var localEndTime = startTime.AddMinutes(61); var utcEndTime = startTime.AddMinutes(1); SetProviderTimes(localEndTime, utcEndTime); _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); localEndTime = localEndTime.AddMinutes(1); utcEndTime = utcEndTime.AddMinutes(1); SetProviderTimes(localEndTime, utcEndTime); _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); // No more messages - no update should be performed 25 minutes after start time because 2 messages came in after that... localEndTime = startTime.AddMinutes(60 + MinutesBeforeFlightClosed); utcEndTime = startTime.AddMinutes(MinutesBeforeFlightClosed); SetProviderTimes(localEndTime, utcEndTime); _HeartbeatService.Raise(s => s.SlowTick += null, EventArgs.Empty); _BaseStationDatabase.Verify(d => d.UpdateFlight(It.IsAny<BaseStationFlight>()), Times.Never()); // But 25 minutes after the last message it should close the flight off localEndTime = startTime.AddMinutes(60 + 2 + MinutesBeforeFlightClosed); utcEndTime = startTime.AddMinutes(2 + MinutesBeforeFlightClosed); SetProviderTimes(localEndTime, utcEndTime); _HeartbeatService.Raise(s => s.SlowTick += null, EventArgs.Empty); _BaseStationDatabase.Verify(d => d.UpdateFlight(It.IsAny<BaseStationFlight>()), Times.Once()); Assert.AreEqual(startTime, flight.StartTime); Assert.AreEqual(startTime.AddMinutes(62), flight.EndTime); }
public void Plugin_Flight_Record_Not_Repeatedly_Inserted_For_Same_Aircraft() { SetEnabledOption(true); BaseStationAircraft aircraft = new BaseStationAircraft() { AircraftID = 5832, ModeS = "X" }; _BaseStationDatabase.Setup(d => d.GetAircraftByCode("X")).Returns(aircraft); _Plugin.Startup(_StartupParameters); var message = new BaseStationMessage() { AircraftId = 99, Icao24 = "X", MessageType = BaseStationMessageType.Transmission, TransmissionType = BaseStationTransmissionType.AirToAir }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); _BaseStationDatabase.Verify(d => d.InsertFlight(It.IsAny<BaseStationFlight>()), Times.Once()); _BaseStationDatabase.Verify(d => d.UpdateFlight(It.IsAny<BaseStationFlight>()), Times.Never()); }
public void Plugin_Flight_Update_Keeps_Callsign_If_Originally_Missing() { SetEnabledOption(true); var startTime = SetProviderTimes(DateTime.Now); _Plugin.Startup(_StartupParameters); var message = new BaseStationMessage() { AircraftId = 99, Icao24 = "X", FlightId = 429, SessionId = 1239, Callsign = null, Altitude = 31, Emergency = true, GroundSpeed = 289, IdentActive = true, Latitude = 31.1F, Longitude = 123.1F, MessageGenerated = DateTime.Now, MessageLogged = DateTime.Now, MessageNumber = 12389, MessageType = BaseStationMessageType.Transmission, OnGround = true, Squawk = 1293, SquawkHasChanged = true, StatusCode = BaseStationStatusCode.None, Track = 12.4F, TransmissionType = BaseStationTransmissionType.AirToAir, VerticalRate = 18 }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); message.Callsign = "ABC123"; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); _BaseStationDatabase.Setup(d => d.UpdateFlight(It.IsAny<BaseStationFlight>())).Callback((BaseStationFlight flight) => { Assert.AreEqual("ABC123", flight.Callsign); }); var endTime = SetProviderTimes(startTime.AddMinutes(MinutesBeforeFlightClosed)); _HeartbeatService.Raise(s => s.SlowTick += null, EventArgs.Empty); _BaseStationDatabase.Verify(d => d.UpdateFlight(It.IsAny<BaseStationFlight>()), Times.Exactly(2)); }
public void Plugin_Database_Not_Touched_If_Writes_Disallowed() { SetEnabledOption(true); SetDBHistory(false); _BaseStationDatabase.Setup(d => d.GetAircraftByCode("X")).Returns((BaseStationAircraft)null); _Plugin.Startup(_StartupParameters); var message = new BaseStationMessage() { AircraftId = 99, Icao24 = "X" }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); _BaseStationDatabase.Verify(d => d.InsertAircraft(It.IsAny<BaseStationAircraft>()), Times.Never()); _BaseStationDatabase.Verify(d => d.UpdateAircraft(It.IsAny<BaseStationAircraft>()), Times.Never()); _BaseStationDatabase.Verify(d => d.InsertFlight(It.IsAny<BaseStationFlight>()), Times.Never()); _BaseStationDatabase.Verify(d => d.UpdateFlight(It.IsAny<BaseStationFlight>()), Times.Never()); }
public void Plugin_Flight_Updates_Status_Bool_Values_Correctly() { // These are the Flight record fields that start with "Had". var worksheet = new ExcelWorksheetData(TestContext); SetEnabledOption(true); BaseStationFlight flight = null; _BaseStationDatabase.Setup(d => d.UpdateFlight(It.IsAny<BaseStationFlight>())).Callback((BaseStationFlight f) => { flight = f; }); _Plugin.Startup(_StartupParameters); var messageProperty = typeof(BaseStationMessage).GetProperty(worksheet.String("MsgProperty")); for(int i = 0;i < worksheet.Int("Count");++i) { var message = new BaseStationMessage() { Icao24 = "Z", MessageType = BaseStationMessageType.Transmission, TransmissionType = BaseStationTransmissionType.AirToAir }; var valueText = worksheet.EString(String.Format("MsgValue{0}", i + 1)); messageProperty.SetValue(message, TestUtilities.ChangeType(valueText, messageProperty.PropertyType, CultureInfo.InvariantCulture), null); _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); } SetProviderTimes(_Provider.Object.LocalNow.AddMinutes(MinutesBeforeFlightClosed)); _HeartbeatService.Raise(s => s.SlowTick += null, EventArgs.Empty); _BaseStationDatabase.Verify(d => d.UpdateFlight(It.IsAny<BaseStationFlight>()), Times.Once()); var propertyName = worksheet.String("FlightProperty"); var flightProperty = typeof(BaseStationFlight).GetProperty(propertyName); var flightValue = worksheet.EString("FlightValue"); var expectedValue = TestUtilities.ChangeType(flightValue, flightProperty.PropertyType, CultureInfo.InvariantCulture); var actualValue = flightProperty.GetValue(flight, null); Assert.AreEqual(expectedValue, actualValue, propertyName); }
public void Plugin_Copes_If_Aircraft_Icao24_Is_Missing_From_Message() { // This will never happen from a compliant feed of messages but we just need to know that if it ever // did arise we would handle it gracefully SetEnabledOption(true); _Plugin.Startup(_StartupParameters); var messageX = new BaseStationMessage() { AircraftId = 99, Icao24 = null }; var messageY = new BaseStationMessage() { AircraftId = 42, Icao24 = "" }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(messageX)); _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(messageY)); _BaseStationDatabase.Verify(d => d.GetAircraftByCode(null), Times.Never()); _BaseStationDatabase.Verify(d => d.GetAircraftByCode(""), Times.Never()); }
public void Plugin_Writes_New_Flight_Record_For_Aircraft_If_Message_Received_After_Final_Update_Of_Previous_Flight() { SetEnabledOption(true); _BaseStationDatabase.Setup(d => d.GetAircraftByCode("Z")).Returns(new BaseStationAircraft() { AircraftID = 4722 }); _BaseStationDatabase.Setup(d => d.InsertSession(It.IsAny<BaseStationSession>())).Callback((BaseStationSession session) => { session.SessionID = 318; }); var message = new BaseStationMessage() { MessageType = BaseStationMessageType.Transmission, TransmissionType = BaseStationTransmissionType.AirToAir, AircraftId = 2372211, SessionId = -1, Icao24 = "Z" }; _Plugin.Startup(_StartupParameters); var time = SetProviderTimes(DateTime.Now); _Listener.Raise(m => m.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); time = SetProviderTimes(time.AddMinutes(MinutesBeforeFlightClosed)); _HeartbeatService.Raise(h => h.SlowTick += null, EventArgs.Empty); _BaseStationDatabase.Setup(d => d.InsertFlight(It.IsAny<BaseStationFlight>())).Callback((BaseStationFlight flight) => { Assert.AreEqual(0, flight.FlightID); Assert.AreEqual(4722, flight.AircraftID); Assert.AreEqual(318, flight.SessionID); Assert.AreEqual(null, flight.Aircraft); Assert.AreEqual("", flight.Callsign); Assert.AreEqual(time, flight.StartTime); Assert.AreEqual(null, flight.EndTime); Assert.AreEqual(null, flight.FirstAltitude); Assert.AreEqual(null, flight.FirstGroundSpeed); Assert.AreEqual(false, flight.FirstIsOnGround); Assert.AreEqual(null, flight.FirstLat); Assert.AreEqual(null, flight.FirstLon); Assert.AreEqual(null, flight.FirstSquawk); Assert.AreEqual(null, flight.FirstTrack); Assert.AreEqual(null, flight.FirstVerticalRate); Assert.AreEqual(false, flight.HadAlert); Assert.AreEqual(false, flight.HadEmergency); Assert.AreEqual(false, flight.HadSpi); Assert.AreEqual(null, flight.LastAltitude); Assert.AreEqual(null, flight.LastGroundSpeed); Assert.AreEqual(false, flight.LastIsOnGround); Assert.AreEqual(null, flight.LastLat); Assert.AreEqual(null, flight.LastLon); Assert.AreEqual(null, flight.LastSquawk); Assert.AreEqual(null, flight.LastTrack); Assert.AreEqual(null, flight.LastVerticalRate); Assert.AreEqual(null, flight.NumADSBMsgRec); Assert.AreEqual(null, flight.NumModeSMsgRec); Assert.AreEqual(null, flight.NumSurPosMsgRec); Assert.AreEqual(null, flight.NumAirPosMsgRec); Assert.AreEqual(null, flight.NumAirVelMsgRec); Assert.AreEqual(null, flight.NumSurAltMsgRec); Assert.AreEqual(null, flight.NumSurIDMsgRec); Assert.AreEqual(null, flight.NumAirToAirMsgRec); Assert.AreEqual(null, flight.NumAirCallRepMsgRec); Assert.AreEqual(null, flight.NumPosMsgRec); }); time = SetProviderTimes(time.AddMilliseconds(1)); _Listener.Raise(m => m.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); _BaseStationDatabase.Verify(d => d.InsertFlight(It.IsAny<BaseStationFlight>()), Times.Exactly(2)); }
public void Plugin_Reports_Exceptions_During_Database_EndTransaction() { var exception = new InvalidOperationException(); SetEnabledOption(true); _BaseStationDatabase.Setup(d => d.EndTransaction()).Callback(() => { throw exception; }); _Plugin.Startup(_StartupParameters); _Plugin.StatusChanged += _StatusChangedEvent.Handler; _StatusChangedEvent.EventRaised += (s, a) => { Assert.AreEqual(String.Format("Exception caught: {0}", exception.Message), _Plugin.StatusDescription); }; var message = new BaseStationMessage() { AircraftId = 99, Icao24 = "X", MessageType = BaseStationMessageType.Transmission, TransmissionType = BaseStationTransmissionType.AirToAir }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); Assert.AreEqual(1, _StatusChangedEvent.CallCount); Assert.AreSame(_Plugin, _StatusChangedEvent.Sender); _Log.Verify(g => g.WriteLine(It.IsAny<string>(), exception.ToString()), Times.Once()); }
public void Plugin_DatabaseFileNameChanging_Flushes_All_Tracked_Flights_To_Disk() { SetEnabledOption(true); _OptionsView.Setup(v => v.DisplayView()).Returns(true); _OptionsView.Setup(v => v.PluginEnabled).Returns(false); _Plugin.Startup(_StartupParameters); var message = new BaseStationMessage() { MessageType = BaseStationMessageType.Transmission, TransmissionType = BaseStationTransmissionType.AirToAir, Icao24 = "Y" }; _Listener.Raise(m => m.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); _BaseStationDatabase.Setup(d => d.UpdateFlight(It.IsAny<BaseStationFlight>())).Callback((BaseStationFlight flight) => { Assert.AreEqual(_Provider.Object.LocalNow, flight.EndTime); Assert.AreEqual(1, flight.NumModeSMsgRec); }); _BaseStationDatabase.Raise(d => d.FileNameChanging += null, EventArgs.Empty); _BaseStationDatabase.Verify(d => d.UpdateFlight(It.IsAny<BaseStationFlight>()), Times.Once()); }
public void Plugin_Flight_Leaves_Callsign_Empty_If_Missing_From_Initial_Message() { SetEnabledOption(true); BaseStationFlight flight = null; _BaseStationDatabase.Setup(d => d.InsertFlight(It.IsAny<BaseStationFlight>())).Callback((BaseStationFlight f) => { flight = f; }); _Plugin.Startup(_StartupParameters); var message = new BaseStationMessage() { AircraftId = 99, Icao24 = "X", FlightId = 429, SessionId = 1239, Callsign = null, MessageType = BaseStationMessageType.Transmission, TransmissionType = BaseStationTransmissionType.AirToAir }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); _BaseStationDatabase.Verify(d => d.InsertFlight(It.IsAny<BaseStationFlight>()), Times.Once()); Assert.AreEqual("", flight.Callsign); }
public void Plugin_Flight_Updated_If_Subsequent_Message_Adds_Callsign() { SetEnabledOption(true); _BaseStationDatabase.Setup(d => d.UpdateFlight(It.IsAny<BaseStationFlight>())).Callback((BaseStationFlight flight) => { // The update must ONLY update the callsign, it isn't allowed to fill in the values that are set when the flight is closed off Assert.AreEqual("ABC123", flight.Callsign); Assert.AreEqual(null, flight.EndTime); Assert.AreEqual(null, flight.FirstAltitude); Assert.AreEqual(null, flight.FirstGroundSpeed); Assert.AreEqual(false, flight.FirstIsOnGround); Assert.AreEqual(null, flight.FirstLat); Assert.AreEqual(null, flight.FirstLon); Assert.AreEqual(null, flight.FirstSquawk); Assert.AreEqual(null, flight.FirstTrack); Assert.AreEqual(null, flight.FirstVerticalRate); Assert.AreEqual(false, flight.HadAlert); Assert.AreEqual(false, flight.HadEmergency); Assert.AreEqual(false, flight.HadSpi); Assert.AreEqual(null, flight.LastAltitude); Assert.AreEqual(null, flight.LastGroundSpeed); Assert.AreEqual(false, flight.LastIsOnGround); Assert.AreEqual(null, flight.LastLat); Assert.AreEqual(null, flight.LastLon); Assert.AreEqual(null, flight.LastSquawk); Assert.AreEqual(null, flight.LastTrack); Assert.AreEqual(null, flight.LastVerticalRate); Assert.AreEqual(null, flight.NumADSBMsgRec); Assert.AreEqual(null, flight.NumModeSMsgRec); Assert.AreEqual(null, flight.NumIDMsgRec); Assert.AreEqual(null, flight.NumSurPosMsgRec); Assert.AreEqual(null, flight.NumAirPosMsgRec); Assert.AreEqual(null, flight.NumAirVelMsgRec); Assert.AreEqual(null, flight.NumSurAltMsgRec); Assert.AreEqual(null, flight.NumSurIDMsgRec); Assert.AreEqual(null, flight.NumAirToAirMsgRec); Assert.AreEqual(null, flight.NumAirCallRepMsgRec); Assert.AreEqual(null, flight.NumPosMsgRec); }); _Plugin.Startup(_StartupParameters); var message = new BaseStationMessage() { AircraftId = 99, Icao24 = "X", FlightId = 429, SessionId = 1239, Callsign = null, Altitude = 31, Emergency = true, GroundSpeed = 289, IdentActive = true, Latitude = 31.1F, Longitude = 123.1F, MessageGenerated = DateTime.Now, MessageLogged = DateTime.Now, MessageNumber = 12389, MessageType = BaseStationMessageType.Transmission, OnGround = true, Squawk = 1293, SquawkHasChanged = true, StatusCode = BaseStationStatusCode.None, Track = 12.4F, TransmissionType = BaseStationTransmissionType.AirToAir, VerticalRate = 18 }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); message.Callsign = "ABC123"; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); _BaseStationDatabase.Verify(d => d.UpdateFlight(It.IsAny<BaseStationFlight>()), Times.Once()); }
/// <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 Plugin_Flight_Not_Updated_After_Callsign_Set() { SetEnabledOption(true); BaseStationFlight flight = null; _BaseStationDatabase.Setup(d => d.UpdateFlight(It.IsAny<BaseStationFlight>())).Callback((BaseStationFlight f) => { flight = f; }); _Plugin.Startup(_StartupParameters); var message = new BaseStationMessage() { MessageType = BaseStationMessageType.Transmission, TransmissionType = BaseStationTransmissionType.AirToAir, AircraftId = 99, Icao24 = "X", FlightId = 429, SessionId = 1239, Callsign = null }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); message = new BaseStationMessage() { MessageType = BaseStationMessageType.Transmission, TransmissionType = BaseStationTransmissionType.AirToAir,AircraftId = 99, Icao24 = "X", FlightId = 429, SessionId = 1239, Callsign = "ABC123" }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); message = new BaseStationMessage() { MessageType = BaseStationMessageType.Transmission, TransmissionType = BaseStationTransmissionType.AirToAir,AircraftId = 99, Icao24 = "X", FlightId = 429, SessionId = 1239, Callsign = "XYZ987" }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); _BaseStationDatabase.Verify(d => d.UpdateFlight(It.IsAny<BaseStationFlight>()), Times.Once()); Assert.AreEqual("ABC123", flight.Callsign); }
/// <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]; }
public void Plugin_Flight_Updated_Correctly_When_Clocks_Go_Backwards_During_Flight() { SetEnabledOption(true); // First message is received when both local and UTC are the same value var startTime = SetProviderTimes(new DateTime(2012, 3, 4, 5, 6, 7)); BaseStationFlight flight = null; _BaseStationDatabase.Setup(d => d.UpdateFlight(It.IsAny<BaseStationFlight>())).Callback((BaseStationFlight f) => { flight = f; }); _Plugin.Startup(_StartupParameters); var message = new BaseStationMessage() { AircraftId = 99, Icao24 = "X", FlightId = 429, SessionId = 1239, Callsign = "ABC123", Altitude = 31, Emergency = true, GroundSpeed = 289, IdentActive = true, Latitude = 31.1F, Longitude = 123.1F, MessageGenerated = DateTime.Now, MessageLogged = DateTime.Now, MessageNumber = 12389, MessageType = BaseStationMessageType.Transmission, OnGround = true, Squawk = 1293, SquawkHasChanged = true, StatusCode = BaseStationStatusCode.None, Track = 12.4F, TransmissionType = BaseStationTransmissionType.AirToAir, VerticalRate = 18 }; _Listener.Raise(r => r.Port30003MessageReceived += null, new BaseStationMessageEventArgs(message)); // Local is localNow one hour behind UTC, so local is 59 minutes behind original start time. // The plugin must recognise that only one minute has elapsed and NOT update the flight record on the database. var localEndTime = startTime.AddMinutes(-59); var utcEndTime = startTime.AddMinutes(1); SetProviderTimes(localEndTime, utcEndTime); _HeartbeatService.Raise(s => s.SlowTick += null, EventArgs.Empty); _BaseStationDatabase.Verify(d => d.UpdateFlight(It.IsAny<BaseStationFlight>()), Times.Never()); // Time moves on and the wait period has elapsed in both local and UTC - the database should localNow be updated localEndTime = localEndTime.AddMinutes(MinutesBeforeFlightClosed); utcEndTime = utcEndTime.AddMinutes(MinutesBeforeFlightClosed); SetProviderTimes(localEndTime, utcEndTime); _HeartbeatService.Raise(s => s.SlowTick += null, EventArgs.Empty); _BaseStationDatabase.Verify(d => d.UpdateFlight(It.IsAny<BaseStationFlight>()), Times.Once()); Assert.AreEqual(startTime, flight.StartTime); Assert.AreEqual(startTime, flight.EndTime); }