public void TestInitialise() { _OriginalClassFactory = Factory.TakeSnapshot(); _HeartbeatService = TestUtilities.CreateMockSingleton<IHeartbeatService>(); _StandingDataManager = TestUtilities.CreateMockSingleton<IStandingDataManager>(); _StandingDataManager.Setup(r => r.FindCodeBlock(It.IsAny<string>())).Returns(new CodeBlock() { Country = "X" }); _StandingDataManager.Setup(r => r.CodeBlocksLoaded).Returns(true); _Statistics = Factory.Singleton.Resolve<IStatistics>().Singleton; _Statistics.Initialise(); _Statistics.ResetConnectionStatistics(); _Statistics.ResetMessageCounters(); _Translator = Factory.Singleton.Resolve<IRawMessageTranslator>(); _Provider = new Mock<IRawMessageTranslatorProvider>() { DefaultValue = DefaultValue.Mock }.SetupAllProperties(); _Provider.Setup(r => r.UtcNow).Returns(new DateTime(1999, 12, 31)); _Translator.Provider = _Provider.Object; _PositionResetEvent = new EventRecorder<EventArgs<string>>(); _Translator.PositionReset += _PositionResetEvent.Handler; _NowUtc = new DateTime(2012, 1, 2, 3, 4, 5, 6); _ModeSMessage = new ModeSMessage() { DownlinkFormat = DownlinkFormat.AllCallReply, Icao24 = 0x112233, ParityInterrogatorIdentifier = 0 }; _AdsbMessage = new AdsbMessage(_ModeSMessage); _RandomIcaos = new List<int>(); }
public void ModeSMessageEventArgs_Constructor_Initialises_To_Known_State() { var dateTimeNow = DateTime.UtcNow; var message = new ModeSMessage(); var adsbMessage = new AdsbMessage(message); var eventArgs = new ModeSMessageEventArgs(dateTimeNow, message, adsbMessage); Assert.AreEqual(dateTimeNow, eventArgs.ReceivedUtc); Assert.AreSame(message, eventArgs.ModeSMessage); Assert.AreSame(adsbMessage, eventArgs.AdsbMessage); }
public void AdsbMessage_Constructor_Initialises_To_Known_Values_And_Properties_Work() { var modeSMessage = new ModeSMessage(); var message = new AdsbMessage(modeSMessage); Assert.AreSame(modeSMessage, message.ModeSMessage); TestUtilities.TestProperty(message, m => m.AirbornePosition, null, new AirbornePositionMessage()); TestUtilities.TestProperty(message, m => m.AirborneVelocity, null, new AirborneVelocityMessage()); TestUtilities.TestProperty(message, m => m.IdentifierAndCategory, null, new IdentifierAndCategoryMessage()); TestUtilities.TestProperty(message, m => m.MessageFormat, MessageFormat.None, MessageFormat.AircraftOperationalStatus); TestUtilities.TestProperty(message, m => m.SurfacePosition, null, new SurfacePositionMessage()); TestUtilities.TestProperty(message, m => m.TargetStateAndStatus, null, new TargetStateAndStatusMessage()); TestUtilities.TestProperty(message, m => m.Type, (byte)0, (byte)255); TestUtilities.TestProperty(message, m => m.AircraftStatus, null, new AircraftStatusMessage()); TestUtilities.TestProperty(message, m => m.AircraftOperationalStatus, null, new AircraftOperationalStatusMessage()); }
/// <summary> /// Decodes an aircraft status message. /// </summary> /// <param name="message"></param> private void DecodeAircraftStatus(AdsbMessage message) { message.MessageFormat = MessageFormat.AircraftStatus; var subMessage = message.AircraftStatus = new AircraftStatusMessage(); subMessage.AircraftStatusType = (AircraftStatusType)_BitStream.ReadByte(3); switch(subMessage.AircraftStatusType) { case AircraftStatusType.EmergencyStatus: var emergency = subMessage.EmergencyStatus = new EmergencyStatus(); emergency.EmergencyState = (EmergencyState)_BitStream.ReadByte(3); var modeA = (short)_BitStream.ReadUInt16(13); if(modeA != 0) emergency.Squawk = ModeS.ModeATranslator.DecodeModeA(modeA); break; case AircraftStatusType.TcasResolutionAdvisoryBroadcast: var tcas = subMessage.TcasResolutionAdvisory = new TcasResolutionAdvisory(); var araCoding = _BitStream.ReadBit(); var araValue = (short)_BitStream.ReadUInt16(13); tcas.ResolutionAdvisoryComplement = (ResolutionAdvisoryComplement)_BitStream.ReadByte(4); tcas.ResolutionAdvisoryTerminated = _BitStream.ReadBit(); tcas.MultipleThreatEncounter = _BitStream.ReadBit(); if(araCoding) tcas.SingleThreatResolutionAdvisory = (SingleThreatResolutionAdvisory)araValue; else if(tcas.MultipleThreatEncounter) tcas.MultipleThreatResolutionAdvisory = (MultipleThreatResolutionAdvisory)araValue; switch(_BitStream.ReadByte(2)) { case 1: tcas.ThreatIcao24 = (int)_BitStream.ReadUInt32(24); break; case 2: var threatAltitude = _BitStream.ReadUInt16(13); var threatRange = _BitStream.ReadByte(7); var threatBearing = _BitStream.ReadByte(6); var strippedAltitude = ((threatAltitude & 0x1F80) >> 2) | ((threatAltitude & 0x20) >> 1) | (threatAltitude & 0x0f); tcas.ThreatAltitude = ModeSAltitudeConversion.LookupGillhamAltitude(strippedAltitude); if(threatRange > 0) { tcas.ThreatRange = ((float)(threatRange - 1) / 10F) + 0.05F; tcas.ThreatRangeExceeded = threatRange == 127; } if(threatBearing > 0 && threatBearing < 61) tcas.ThreatBearing = (short)((threatBearing - 1) * 6); break; } break; } }
/// <summary> /// Decodes an airborne position message. /// </summary> /// <param name="message"></param> private void DecodeAirbornePosition(AdsbMessage message) { message.MessageFormat = message.Type == 0 ? MessageFormat.NoPositionInformation : MessageFormat.AirbornePosition; var subMessage = message.AirbornePosition = new AirbornePositionMessage(); subMessage.SurveillanceStatus = (SurveillanceStatus)_BitStream.ReadByte(2); if(message.Type == 0) _BitStream.Skip(1); else subMessage.NicB = (byte)(_BitStream.ReadBit() ? 2 : 0); var rawAltitude = _BitStream.ReadUInt16(12); var acCode = ((rawAltitude & 0xfe0) >> 1) | (rawAltitude & 0x0f); int? altitude = null; if((rawAltitude & 0x10) != 0) altitude = ModeSAltitudeConversion.CalculateBinaryAltitude(acCode); else altitude= ModeSAltitudeConversion.LookupGillhamAltitude(acCode); if(message.Type < 20) subMessage.BarometricAltitude = altitude; else subMessage.GeometricAltitude = altitude; subMessage.PositionTimeIsExact = _BitStream.ReadBit(); subMessage.CompactPosition = ExtractCprCoordinate(message, 17); }
/// <summary> /// Decodes the content of aircraft operational status messages. /// </summary> /// <param name="message"></param> private void DecodeAircraftOperationalStatus(AdsbMessage message) { message.MessageFormat = MessageFormat.AircraftOperationalStatus; var subMessage = message.AircraftOperationalStatus = new AircraftOperationalStatusMessage(); var subType = _BitStream.ReadByte(3); subMessage.AircraftOperationalStatusType = (AircraftOperationalStatusType)subType; bool isSurfaceCapability = subMessage.AircraftOperationalStatusType == AircraftOperationalStatusType.SurfaceCapability; var cc = _BitStream.ReadUInt16(isSurfaceCapability ? 12 : 16); var len = isSurfaceCapability ? _BitStream.ReadByte(4) : (byte)0; var om = _BitStream.ReadUInt16(16); var version = subMessage.AdsbVersion = _BitStream.ReadByte(3); if(version < 3 && subType < 2) { switch(subType) { case 0: subMessage.AirborneCapability = cc; break; case 1: if(version > 0) { subMessage.SurfaceCapability = (SurfaceCapability)cc; if(version != 0 && (version != 2 || len != 0)) { subMessage.MaximumLength = _MaximumLengths[len]; subMessage.MaximumWidth = _MaximumWidths[len]; } } break; } if(version > 0) { subMessage.OperationalMode = (OperationalMode)om; if(version == 2) { subMessage.SystemDesignAssurance = (SystemDesignAssurance)((om & 0x300) >> 8); if(subType == 1) { var gpsRight = (om & 0x80); var gpsLat = (om & 0x60) >> 5; var gpsLon = om & 0x1f; if(gpsRight != 0 || gpsLat != 0) subMessage.LateralAxisGpsOffset = (short)((gpsRight != 0 ? -1 : 1) * (gpsLat * 2)); if(gpsLon > 1) subMessage.LongitudinalAxisGpsOffset = (byte)((gpsLon - 1) * 2); } } subMessage.NicA = _BitStream.ReadBit() ? (byte)4 : (byte)0; if(version == 2 && subType == 1) subMessage.NicC = (byte)(om & 0x01); subMessage.NacP = _BitStream.ReadByte(4); if(version == 2 && subType == 0) subMessage.Gva = _BitStream.ReadByte(2); else _BitStream.Skip(2); subMessage.Sil = _BitStream.ReadByte(2); if(subType == 0) subMessage.NicBaro = _BitStream.ReadBit(); else subMessage.SurfacePositionAngleIsTrack = _BitStream.ReadBit(); subMessage.HorizontalReferenceIsMagneticNorth = _BitStream.ReadBit(); if(version == 2) { subMessage.SilSupplement = _BitStream.ReadBit(); subMessage.IsRebroadcast = _BitStream.ReadBit(); } } } }
private void ApplyAdsbAircraftStatus(AdsbMessage adsbMessage, BaseStationMessage baseStationMessage) { if(adsbMessage.AircraftStatus.EmergencyStatus != null) { baseStationMessage.Squawk = adsbMessage.AircraftStatus.EmergencyStatus.Squawk; baseStationMessage.Emergency = adsbMessage.AircraftStatus.EmergencyStatus.EmergencyState != EmergencyState.None; } }
/// <summary> /// See interface docs. /// </summary> /// <param name="modeSMessage"></param> /// <returns></returns> public AdsbMessage Translate(ModeSMessage modeSMessage) { AdsbMessage result = null; if(modeSMessage != null && modeSMessage.ExtendedSquitterMessage != null && modeSMessage.ExtendedSquitterMessage.Length == 7) { _BitStream.Initialise(modeSMessage.ExtendedSquitterMessage); result = new AdsbMessage(modeSMessage); result.Type = _BitStream.ReadByte(5); switch(result.Type) { case 0: DecodeAirbornePosition(result); break; case 1: case 2: case 3: case 4: DecodeIdentification(result); break; case 5: case 6: case 7: case 8: DecodeSurfacePosition(result); break; case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: DecodeAirbornePosition(result); break; case 19: DecodeVelocity(result); break; case 20: case 21: case 22: DecodeAirbornePosition(result); break; case 28: DecodeAircraftStatus(result); break; case 29: DecodeTargetStateAndStatus(result); break; case 31: DecodeAircraftOperationalStatus(result); break; } if(_Statistics.Lock != null) { lock(_Statistics.Lock) { ++_Statistics.AdsbCount; ++_Statistics.AdsbMessageFormatCount[(int)result.MessageFormat]; ++_Statistics.AdsbTypeCount[result.Type]; } } } return result; }
/// <summary> /// Decodes the target state and status message. /// </summary> /// <param name="message"></param> private void DecodeTargetStateAndStatus(AdsbMessage message) { message.MessageFormat = MessageFormat.TargetStateAndStatus; var subMessage = message.TargetStateAndStatus = new TargetStateAndStatusMessage(); subMessage.TargetStateAndStatusType = (TargetStateAndStatusType)_BitStream.ReadByte(2); switch(subMessage.TargetStateAndStatusType) { case TargetStateAndStatusType.Version1: var verticalDataSource = (VerticalDataSource)_BitStream.ReadByte(2); var altitudeIsMeanSeaLevel = _BitStream.ReadBit(); if(!_BitStream.ReadBit()) { // backwards compatibility bit - if this is non-zero then it's a version 0 TCP message that we need to ignore var version1 = subMessage.Version1 = new TargetStateAndStatusVersion1(); version1.VerticalDataSource = verticalDataSource; version1.AltitudesAreMeanSeaLevel = altitudeIsMeanSeaLevel; version1.TargetAltitudeCapability = (TargetAltitudeCapability)_BitStream.ReadByte(2); version1.VerticalModeIndicator = (VerticalModeIndicator)_BitStream.ReadByte(2); var altitude = (int)_BitStream.ReadUInt16(10); if(version1.VerticalDataSource != VerticalDataSource.None && altitude < 1011) version1.TargetAltitude = (altitude * 100) - 1000; version1.HorizontalDataSource = (HorizontalDataSource)_BitStream.ReadByte(2); var heading = _BitStream.ReadUInt16(9); if(version1.HorizontalDataSource != HorizontalDataSource.None && heading < 360) version1.TargetHeading = (short)heading; version1.TargetHeadingIsTrack = _BitStream.ReadBit(); version1.HorizontalModeIndicator = (HorizontalModeIndicator)_BitStream.ReadByte(2); version1.NacP = _BitStream.ReadByte(4); version1.NicBaro = _BitStream.ReadBit(); version1.Sil = _BitStream.ReadByte(2); _BitStream.Skip(5); version1.TcasCapabilityMode = (TcasCapabilityMode)_BitStream.ReadByte(2); version1.EmergencyState = (EmergencyState)_BitStream.ReadByte(3); } break; case TargetStateAndStatusType.Version2: var version2 = message.TargetStateAndStatus.Version2 = new TargetStateAndStatusVersion2(); version2.SilSupplement = _BitStream.ReadBit(); version2.SelectedAltitudeIsFms = _BitStream.ReadBit(); var selAltitude = _BitStream.ReadUInt16(11); if(selAltitude != 0) version2.SelectedAltitude = (selAltitude - 1) * 32; var pressure = _BitStream.ReadUInt16(9); if(pressure != 0) version2.BarometricPressureSetting = (((float)pressure - 1F) * 0.8F) + 800F; bool headingIsValid = _BitStream.ReadBit(); var headingValue = _BitStream.ReadUInt16(9); if(headingIsValid) version2.SelectedHeading = (double)headingValue * 0.703125; version2.NacP = _BitStream.ReadByte(4); version2.NicBaro = _BitStream.ReadBit(); version2.Sil = _BitStream.ReadByte(2); var autopilotValid = _BitStream.ReadBit(); version2.IsAutopilotEngaged = _BitStream.ReadBit(); version2.IsVnavEngaged = _BitStream.ReadBit(); version2.IsAltitudeHoldActive = _BitStream.ReadBit(); version2.IsRebroadcast = _BitStream.ReadBit(); version2.IsApproachModeActive = _BitStream.ReadBit(); version2.IsTcasOperational = _BitStream.ReadBit(); version2.IsLnavEngaged = _BitStream.ReadBit(); if(!autopilotValid) { version2.IsAutopilotEngaged = version2.IsVnavEngaged = version2.IsAltitudeHoldActive = version2.IsApproachModeActive = version2.IsLnavEngaged = null; } break; } }
/// <summary> /// Extracts the fields describing a Compact Position Reporting coordinate in a message. /// </summary> /// <param name="message"></param> /// <param name="encodingBits"></param> /// <returns></returns> private CompactPositionReportingCoordinate ExtractCprCoordinate(AdsbMessage message, byte encodingBits) { CompactPositionReportingCoordinate result = null; if(message.Type != 0) { bool isOddFormat = _BitStream.ReadBit(); int latitude = (int)_BitStream.ReadUInt32(17); int longitude = (int)_BitStream.ReadUInt32(17); result = new CompactPositionReportingCoordinate(latitude, longitude, isOddFormat, encodingBits); } return result; }
/// <summary> /// Creates a BaseStationMessage from the Mode-S and ADS-B message passed across. /// </summary> /// <param name="messageReceivedUtc"></param> /// <param name="modeSMessage"></param> /// <param name="adsbMessage"></param> /// <param name="trackedAircraft"></param> /// <returns></returns> private BaseStationMessage CreateBaseStationMessage(DateTime messageReceivedUtc, ModeSMessage modeSMessage, AdsbMessage adsbMessage, TrackedAircraft trackedAircraft) { var result = new BaseStationMessage() { MessageType = BaseStationMessageType.Transmission, TransmissionType = ConvertToTransmissionType(modeSMessage, adsbMessage), MessageGenerated = messageReceivedUtc, MessageLogged = messageReceivedUtc, Icao24 = modeSMessage.FormattedIcao24, Altitude = modeSMessage.Altitude, Squawk = modeSMessage.Identity, }; ApplyModeSValues(modeSMessage, trackedAircraft, result); if(adsbMessage != null) ApplyAdsbValues(messageReceivedUtc, adsbMessage, trackedAircraft, result); result.GroundSpeed = Round.GroundSpeed(result.GroundSpeed); result.Track = Round.Track(result.Track); result.Latitude = Round.Coordinate(result.Latitude); result.Longitude = Round.Coordinate(result.Longitude); return result; }
public void RawMessageTranslator_Translate_Extracts_Position_From_ADSB_Messages_Correctly() { var worksheet = new ExcelWorksheetData(TestContext); _Translator.ReceiverLocation = ParseGlobalPosition(worksheet.String("ReceiverPosn")); _Translator.ReceiverRangeKilometres = worksheet.Int("Range"); _Translator.GlobalDecodeAirborneThresholdMilliseconds = worksheet.Int("GATS"); _Translator.GlobalDecodeFastSurfaceThresholdMilliseconds = worksheet.Int("GFSTS"); _Translator.GlobalDecodeSlowSurfaceThresholdMilliseconds = worksheet.Int("GSSTS"); _Translator.LocalDecodeMaxSpeedAirborne = worksheet.Double("LAMS"); _Translator.LocalDecodeMaxSpeedTransition = worksheet.Double("LTMS"); _Translator.LocalDecodeMaxSpeedSurface = worksheet.Double("LSMS"); _Translator.SuppressReceiverRangeCheck = worksheet.Bool("SRRC"); _Translator.UseLocalDecodeForInitialPosition = worksheet.Bool("ULD"); DateTime now = DateTime.UtcNow; for(var i = 1;i <= 4;++i) { var millisecondsColumn = String.Format("MSec{0}", i); var cprColumn = String.Format("CPR{0}", i); var speedColumn = String.Format("Spd{0}", i); var positionColumn = String.Format("Posn{0}", i); if(worksheet.String(cprColumn) == null) continue; var cpr = ParseCpr(worksheet.String(cprColumn)); var speed = worksheet.NDouble(speedColumn); var expectedPosition = ParseGlobalPosition(worksheet.String(positionColumn)); if(i != 1 && worksheet.String(millisecondsColumn) != null) { now = now.AddMilliseconds(worksheet.Int(millisecondsColumn)); } var modeSMessage = new ModeSMessage() { DownlinkFormat = DownlinkFormat.ExtendedSquitter, Icao24 = 0x112233, ParityInterrogatorIdentifier = 0 }; var adsbMessage = new AdsbMessage(modeSMessage); switch(cpr.NumberOfBits) { case 17: adsbMessage.MessageFormat = MessageFormat.AirbornePosition; adsbMessage.AirbornePosition = new AirbornePositionMessage() { CompactPosition = cpr }; break; case 19: adsbMessage.MessageFormat = MessageFormat.SurfacePosition; adsbMessage.SurfacePosition = new SurfacePositionMessage() { CompactPosition = cpr, GroundSpeed = speed, }; break; } var baseStationMessage = _Translator.Translate(now, modeSMessage, adsbMessage); var failMessage = String.Format("Failed on message {0}", i); if(expectedPosition == null) { if(baseStationMessage != null) { if(baseStationMessage.Latitude != null || baseStationMessage.Longitude != null) { Assert.Fail(String.Format("Position decoded to {0}/{1} erroneously. {2}", baseStationMessage.Latitude, baseStationMessage.Longitude, failMessage)); } } } else { Assert.IsNotNull(baseStationMessage.Latitude, failMessage); Assert.IsNotNull(baseStationMessage.Longitude, failMessage); Assert.AreEqual(expectedPosition.Latitude, baseStationMessage.Latitude.Value, 0.0001, failMessage); Assert.AreEqual(expectedPosition.Longitude, baseStationMessage.Longitude.Value, 0.0001, failMessage); } } Assert.AreEqual(worksheet.Int("ResetCount"), _PositionResetEvent.CallCount); Assert.AreEqual(worksheet.Int("ResetCount") > 0 ? 1L : 0L, _Statistics.AdsbPositionsReset); Assert.AreEqual(worksheet.Long("BadRange"), _Statistics.AdsbPositionsOutsideRange); Assert.AreEqual(worksheet.Long("BadSpeed"), _Statistics.AdsbPositionsExceededSpeedCheck); }
/// <summary> /// Applies values from the ADS-B message to the BaseStation message being formed. /// </summary> /// <param name="messageReceivedUtc"></param> /// <param name="adsbMessage"></param> /// <param name="trackedAircraft"></param> /// <param name="baseStationMessage"></param> private void ApplyAdsbValues(DateTime messageReceivedUtc, AdsbMessage adsbMessage, TrackedAircraft trackedAircraft, BaseStationMessage baseStationMessage) { if(adsbMessage.AirbornePosition != null) ApplyAdsbAirbornePosition(messageReceivedUtc, adsbMessage, trackedAircraft, baseStationMessage); if(adsbMessage.AirborneVelocity != null) ApplyAdsbAirborneVelocity(adsbMessage, baseStationMessage); if(adsbMessage.AircraftStatus != null) ApplyAdsbAircraftStatus(adsbMessage, baseStationMessage); if(adsbMessage.IdentifierAndCategory != null) ApplyAdsbIdentifierAndCategory(adsbMessage, trackedAircraft, baseStationMessage); if(adsbMessage.SurfacePosition != null) ApplyAdsbSurfacePosition(messageReceivedUtc, adsbMessage, trackedAircraft, baseStationMessage); if(adsbMessage.TargetStateAndStatus != null) ApplyAdsbTargetStateAndStatus(adsbMessage, baseStationMessage); }
/// <summary> /// Returns the transmission type corresponding to raw messages passed across. /// </summary> /// <param name="modeSMessage"></param> /// <param name="adsbMessage"></param> /// <returns></returns> private BaseStationTransmissionType ConvertToTransmissionType(ModeSMessage modeSMessage, AdsbMessage adsbMessage) { BaseStationTransmissionType result = BaseStationTransmissionType.None; if(adsbMessage == null) { switch(modeSMessage.DownlinkFormat) { case DownlinkFormat.CommBAltitudeReply: case DownlinkFormat.SurveillanceAltitudeReply: result = BaseStationTransmissionType.SurveillanceAlt; break; case DownlinkFormat.CommBIdentityReply: case DownlinkFormat.SurveillanceIdentityReply: result = BaseStationTransmissionType.SurveillanceId; break; case DownlinkFormat.CommD: case DownlinkFormat.ExtendedSquitter: case DownlinkFormat.ExtendedSquitterNonTransponder: case DownlinkFormat.MilitaryExtendedSquitter: case DownlinkFormat.AllCallReply: result = BaseStationTransmissionType.AllCallReply; break; case DownlinkFormat.LongAirToAirSurveillance: case DownlinkFormat.ShortAirToAirSurveillance: result = BaseStationTransmissionType.AirToAir; break; default: throw new NotImplementedException(); } } else { switch(adsbMessage.MessageFormat) { case MessageFormat.AirbornePosition: result = BaseStationTransmissionType.AirbornePosition; break; case MessageFormat.AirborneVelocity: result = BaseStationTransmissionType.AirborneVelocity; break; case MessageFormat.IdentificationAndCategory: result = BaseStationTransmissionType.IdentificationAndCategory; break; case MessageFormat.SurfacePosition: result = BaseStationTransmissionType.SurfacePosition; break; case MessageFormat.AircraftOperationalStatus: case MessageFormat.AircraftStatus: case MessageFormat.None: case MessageFormat.NoPositionInformation: case MessageFormat.TargetStateAndStatus: result = BaseStationTransmissionType.AllCallReply; break; } } return result; }
private void ApplyAdsbTargetStateAndStatus(AdsbMessage adsbMessage, BaseStationMessage baseStationMessage) { if(adsbMessage.TargetStateAndStatus.Version1 != null) { baseStationMessage.Emergency = adsbMessage.TargetStateAndStatus.Version1.EmergencyState != EmergencyState.None; } }
private void ApplyAdsbSurfacePosition(DateTime messageReceivedUtc, AdsbMessage adsbMessage, TrackedAircraft trackedAircraft, BaseStationMessage baseStationMessage) { baseStationMessage.OnGround = true; baseStationMessage.GroundSpeed = (float?)adsbMessage.SurfacePosition.GroundSpeed; baseStationMessage.Track = (float?)adsbMessage.SurfacePosition.GroundTrack; if(adsbMessage.SurfacePosition.IsReversing) { if(baseStationMessage.Supplementary == null) baseStationMessage.Supplementary = new BaseStationSupplementaryMessage(); baseStationMessage.Supplementary.SpeedType = SpeedType.GroundSpeedReversing; } if(adsbMessage.SurfacePosition.CompactPosition != null) { trackedAircraft.RecordMessage(messageReceivedUtc, adsbMessage.SurfacePosition.CompactPosition); DecodePosition(baseStationMessage, trackedAircraft, adsbMessage.SurfacePosition.GroundSpeed); } }
private void ApplyAdsbIdentifierAndCategory(AdsbMessage adsbMessage, TrackedAircraft trackedAircraft, BaseStationMessage baseStationMessage) { if(adsbMessage.IdentifierAndCategory.Identification != null) { trackedAircraft.SeenAdsbCallsign = true; baseStationMessage.Callsign = adsbMessage.IdentifierAndCategory.Identification.Trim(); if(baseStationMessage.Supplementary == null) baseStationMessage.Supplementary = new BaseStationSupplementaryMessage(); baseStationMessage.Supplementary.CallsignIsSuspect = false; } }
/// <summary> /// Decodes an identification and emitter category message. /// </summary> /// <param name="message"></param> private void DecodeIdentification(AdsbMessage message) { message.MessageFormat = MessageFormat.IdentificationAndCategory; var subMessage = message.IdentifierAndCategory = new IdentifierAndCategoryMessage(); subMessage.EmitterCategory = _EmitterCategories[message.Type - 1, _BitStream.ReadByte(3)]; subMessage.Identification = ModeSCharacterTranslator.ExtractCharacters(_BitStream, 8); }
/// <summary> /// See interface docs. /// </summary> /// <param name="messageReceivedUtc"></param> /// <param name="modeSMessage"></param> /// <param name="adsbMessage"></param> /// <returns></returns> public BaseStationMessage Translate(DateTime messageReceivedUtc, ModeSMessage modeSMessage, AdsbMessage adsbMessage) { BaseStationMessage result = null; if(modeSMessage != null && !_Disposed) { var isValidMessage = DetermineWhetherValid(modeSMessage, messageReceivedUtc); if(isValidMessage) { TrackedAircraft trackedAircraft; lock(_TrackedAircraftLock) { if(!_TrackedAircraft.TryGetValue(modeSMessage.Icao24, out trackedAircraft)) { trackedAircraft = new TrackedAircraft() { Icao24 = modeSMessage.FormattedIcao24, LatestMessageUtc = messageReceivedUtc, }; _TrackedAircraft.Add(modeSMessage.Icao24, trackedAircraft); } else { if((messageReceivedUtc - trackedAircraft.LatestMessageUtc).TotalSeconds >= TrackingTimeoutSeconds) { trackedAircraft = new TrackedAircraft() { Icao24 = modeSMessage.FormattedIcao24 }; _TrackedAircraft[modeSMessage.Icao24] = trackedAircraft; } trackedAircraft.LatestMessageUtc = messageReceivedUtc; } } if(isValidMessage) { result = CreateBaseStationMessage(messageReceivedUtc, modeSMessage, adsbMessage, trackedAircraft); if(_Statistics.Lock != null) { lock(_Statistics.Lock) _Statistics.AdsbAircraftTracked = _TrackedAircraft.Count; } } } } return result; }
/// <summary> /// Decodes a surface position message. /// </summary> /// <param name="message"></param> private void DecodeSurfacePosition(AdsbMessage message) { message.MessageFormat = MessageFormat.SurfacePosition; var subMessage = message.SurfacePosition = new SurfacePositionMessage(); var movement = _BitStream.ReadByte(7); if(movement > 0) { if(movement < 124) subMessage.GroundSpeed = _SurfaceGroundSpeed[movement]; else if(movement == 124) { subMessage.GroundSpeed = 175.0; subMessage.GroundSpeedExceeded = true; } else if(movement == 127) { subMessage.IsReversing = true; } } var trackIsValid = _BitStream.ReadBit(); var track = _BitStream.ReadByte(7); if(trackIsValid) subMessage.GroundTrack = track * 2.8125; subMessage.PositionTimeIsExact = _BitStream.ReadBit(); subMessage.CompactPosition = ExtractCprCoordinate(message, 19); }
private void ApplyAdsbAirbornePosition(DateTime messageReceivedUtc, AdsbMessage adsbMessage, TrackedAircraft trackedAircraft, BaseStationMessage baseStationMessage) { if(adsbMessage.AirbornePosition.BarometricAltitude != null) baseStationMessage.Altitude = adsbMessage.AirbornePosition.BarometricAltitude; else if(adsbMessage.AirbornePosition.GeometricAltitude != null) { baseStationMessage.Altitude = adsbMessage.AirbornePosition.GeometricAltitude; if(baseStationMessage.Supplementary == null) baseStationMessage.Supplementary = new BaseStationSupplementaryMessage(); baseStationMessage.Supplementary.AltitudeIsGeometric = true; } if(adsbMessage.AirbornePosition.CompactPosition != null) { trackedAircraft.RecordMessage(messageReceivedUtc, adsbMessage.AirbornePosition.CompactPosition); DecodePosition(baseStationMessage, trackedAircraft, null); } baseStationMessage.SquawkHasChanged = adsbMessage.AirbornePosition.SurveillanceStatus == SurveillanceStatus.TemporaryAlert; baseStationMessage.IdentActive = adsbMessage.AirbornePosition.SurveillanceStatus == SurveillanceStatus.SpecialPositionIdentification; }
/// <summary> /// Decodes an airborne velocity message. /// </summary> /// <param name="message"></param> private void DecodeVelocity(AdsbMessage message) { message.MessageFormat = MessageFormat.AirborneVelocity; var subMessage = message.AirborneVelocity = new AirborneVelocityMessage(); var velocityType = _BitStream.ReadByte(3); subMessage.VelocityType = (VelocityType)velocityType; if(velocityType > 0 && velocityType < 5) { subMessage.ChangeOfIntent = _BitStream.ReadBit(); _BitStream.Skip(1); switch(_BitStream.ReadByte(3)) { case 0: subMessage.HorizontalVelocityError = 10F; break; case 1: subMessage.HorizontalVelocityError = -10F; break; case 2: subMessage.HorizontalVelocityError = -3F; break; case 3: subMessage.HorizontalVelocityError = -1F; break; case 4: subMessage.HorizontalVelocityError = -0.3F; break; } if(velocityType == 3 || velocityType == 4) { var headingAvailable = _BitStream.ReadBit(); var heading = _BitStream.ReadUInt16(10); if(headingAvailable) subMessage.Heading = (double)heading * 0.3515625; subMessage.AirspeedIsTrueAirspeed = _BitStream.ReadBit(); var airspeed = _BitStream.ReadUInt16(10); if(airspeed != 0) { if(airspeed == 1023) subMessage.AirspeedExceeded = true; subMessage.Airspeed = airspeed - 1; if(velocityType == 4) subMessage.Airspeed *= 4; } } else { var vector = subMessage.VectorVelocity = new VectorVelocity() { IsWesterlyVelocity = _BitStream.ReadBit(), EastWestVelocity = (short?)_BitStream.ReadUInt16(10), IsSoutherlyVelocity = _BitStream.ReadBit(), NorthSouthVelocity = (short?)_BitStream.ReadUInt16(10), }; if(vector.EastWestVelocity == 0) vector.EastWestVelocity = null; else { vector.EastWestExceeded = vector.EastWestVelocity == 1023; vector.EastWestVelocity = (short)((vector.EastWestVelocity - 1) * (velocityType == 1 ? 1 : 4)); } if(vector.NorthSouthVelocity == 0) vector.NorthSouthVelocity = null; else { vector.NorthSouthExceeded = vector.NorthSouthVelocity == 1023; vector.NorthSouthVelocity = (short)((vector.NorthSouthVelocity - 1) * (velocityType == 1 ? 1 : 4)); } } subMessage.VerticalRateIsBarometric = _BitStream.ReadBit(); var verticalRateSign = _BitStream.ReadBit() ? -1 : 1; var verticalRate = _BitStream.ReadUInt16(9); if(verticalRate != 0) { subMessage.VerticalRateExceeded = verticalRateSign == 511; subMessage.VerticalRate = verticalRateSign * ((verticalRate - 1) * 64); } _BitStream.Skip(2); var geometricDeltaSign = _BitStream.ReadBit() ? -1 : 1; var geometricDelta = _BitStream.ReadByte(7); if(geometricDelta != 0) { subMessage.GeometricAltitudeDeltaExceeded = geometricDelta == 127; subMessage.GeometricAltitudeDelta = (short)(geometricDeltaSign * ((geometricDelta - 1) * 25)); } } }
/// <summary> /// Creates a new object. /// </summary> /// <param name="utcNow"></param> /// <param name="modeSMessage"></param> /// <param name="adsbMessage"></param> public ModeSMessageEventArgs(DateTime utcNow, ModeSMessage modeSMessage, AdsbMessage adsbMessage) { ReceivedUtc = utcNow; ModeSMessage = modeSMessage; AdsbMessage = adsbMessage; }
public 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; }
private void ApplyAdsbAirborneVelocity(AdsbMessage adsbMessage, BaseStationMessage baseStationMessage) { if(adsbMessage.AirborneVelocity.VectorVelocity != null) { baseStationMessage.GroundSpeed = (float?)adsbMessage.AirborneVelocity.VectorVelocity.Speed; baseStationMessage.Track = (float?)adsbMessage.AirborneVelocity.VectorVelocity.Bearing; } else if(adsbMessage.AirborneVelocity.VelocityType == VelocityType.AirspeedSubsonic || adsbMessage.AirborneVelocity.VelocityType == VelocityType.AirspeedSupersonic) { baseStationMessage.GroundSpeed = (float?)adsbMessage.AirborneVelocity.Airspeed; baseStationMessage.Track = (float?)adsbMessage.AirborneVelocity.Heading; if(baseStationMessage.Supplementary == null) baseStationMessage.Supplementary = new BaseStationSupplementaryMessage(); baseStationMessage.Supplementary.SpeedType = adsbMessage.AirborneVelocity.AirspeedIsTrueAirspeed ? SpeedType.TrueAirSpeed : SpeedType.IndicatedAirSpeed; baseStationMessage.Supplementary.TrackIsHeading = true; } baseStationMessage.VerticalRate = adsbMessage.AirborneVelocity.VerticalRate; if(adsbMessage.AirborneVelocity.VerticalRateIsBarometric) { if(baseStationMessage.Supplementary == null) baseStationMessage.Supplementary = new BaseStationSupplementaryMessage(); baseStationMessage.Supplementary.VerticalRateIsGeometric = true; } }