/// <summary> /// Decodes the fields from an extended squitter reply (DF = 17). /// </summary> /// <param name="reply"></param> private void DecodeExtendedSquitter(ModeSMessage reply) { ExtractCapability(reply); ExtractAircraftAddress(reply); ExtractExtendedSquitterMessage(reply); ExtractParityInterrogator(reply); }
/// <summary> /// Decodes the fields from a surveillance identity reply (DF = 5). /// </summary> /// <param name="reply"></param> private void DecodeSurveillanceIdentityReply(ModeSMessage reply) { ExtractFlightStatus(reply); ExtractDownlinkRequest(reply); ExtractUtilityMessage(reply); ExtractIdentity(reply); ExtractAircraftParityIdentifier(reply); }
/// <summary> /// Decodes the fields from a Comm-D reply (DF = 24). /// </summary> /// <param name="reply"></param> private void DecodeCommD(ModeSMessage reply) { _BitStream.Skip(1); reply.ElmControl = (ElmControl)_BitStream.ReadByte(1); reply.DSegmentNumber = _BitStream.ReadByte(4); reply.CommDMessage = ReadBytes(10); ExtractAircraftParityIdentifier(reply); }
/// <summary> /// Decodes the fields from a Comm-B altitude reply (DF = 20). /// </summary> /// <param name="reply"></param> private void DecodeCommBAltitudeReply(ModeSMessage reply) { ExtractFlightStatus(reply); ExtractDownlinkRequest(reply); ExtractUtilityMessage(reply); ExtractAltitudeCode(reply); ExtractCommBMessage(reply); ExtractAircraftParityIdentifier(reply); }
private void ExtractCommBMessage(ModeSMessage reply) { reply.CommBMessage = ReadBytes(7); if (reply.CommBMessage[0] == 0x20) { _BitStream.Skip(-48); reply.PossibleCallsign = ModeSCharacterTranslator.ExtractCharacters(_BitStream, 8); } }
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); }
/// <summary> /// Decodes the fields from a long air-to-air surveillance reply (DF = 16). /// </summary> /// <param name="reply"></param> private void DecodeLongAirToAirSurveillance(ModeSMessage reply) { ExtractVerticalStatus(reply); _BitStream.Skip(2); ExtractSensitivityLevel(reply); _BitStream.Skip(2); ExtractReplyInformation(reply); _BitStream.Skip(2); ExtractAltitudeCode(reply); reply.ACASMessage = ReadBytes(7); ExtractAircraftParityIdentifier(reply); }
/// <summary> /// Decodes the fields from a short air-to-air surveillance reply (DF = 0). /// </summary> /// <param name="reply"></param> private void DecodeShortAirToAirSurveillance(ModeSMessage reply) { ExtractVerticalStatus(reply); reply.CrossLinkCapability = _BitStream.ReadBit(); _BitStream.Skip(1); ExtractSensitivityLevel(reply); _BitStream.Skip(2); ExtractReplyInformation(reply); _BitStream.Skip(2); ExtractAltitudeCode(reply); ExtractAircraftParityIdentifier(reply); }
/// <summary> /// Decodes the fields from a military extended squitter reply (DF = 19). /// </summary> /// <param name="reply"></param> private void DecodeMilitaryExtendedSquitter(ModeSMessage reply) { reply.ApplicationField = (ApplicationField)_BitStream.ReadByte(3); if (reply.ApplicationField != ApplicationField.ADSB) { reply.ExtendedSquitterSupplementaryMessage = ReadBytes(13); } else { ExtractAircraftAddress(reply); ExtractExtendedSquitterMessage(reply); ExtractParityInterrogator(reply); } }
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()); }
private void ExtractAltitudeCode(ModeSMessage reply) { reply.Altitude = _BitStream.ReadUInt16(13); reply.AltitudeIsMetric = (reply.Altitude & 0x40) != 0; if (!reply.AltitudeIsMetric.Value) { int?decodedAltitude = ((reply.Altitude & 0x1F80) >> 2) | ((reply.Altitude & 0x20) >> 1) | (reply.Altitude & 0x0f); if ((reply.Altitude & 0x10) != 0) { decodedAltitude = ModeSAltitudeConversion.CalculateBinaryAltitude(decodedAltitude.Value); } else { decodedAltitude = ModeSAltitudeConversion.LookupGillhamAltitude(decodedAltitude.Value); } reply.Altitude = decodedAltitude; } }
public PointLatLngAlt pllalocal(ModeSMessage newmsg) { if (newmsg == null) return PointLatLngAlt.Zero; int num = 131072; double denominator = (newmsg.OddFormat ? 6.101694915254237 : 6.0); double num3 = 360.0; double latitude = reflat; double num5 = ((double)newmsg.lat) / ((double)num); double num6 = Math.Floor((double)(latitude / denominator)) + Math.Floor((double)((0.5 + (this.modulo(latitude, denominator) / denominator)) - num5)); double lat = denominator * (num6 + num5); int num7 = this.NL(newmsg.lat) - (newmsg.OddFormat ? 1 : 0); double numerator = reflng; double num9 = (num7 == 0) ? num3 : (num3 / ((double)num7)); double num10 = ((double)newmsg.lng) / ((double)num); double num11 = Math.Floor((double)(numerator / num9)) + Math.Floor((double)((0.5 + (this.modulo(numerator, num9) / num9)) - num10)); double lng = num9 * (num11 + num10); return new PointLatLngAlt(lat,lng); }
/// <summary> /// Decodes the fields from an extended squitter from non-transponder reply (DF = 18). /// </summary> /// <param name="reply"></param> private void DecodeExtendedSquitterNonTransponder(ModeSMessage reply) { reply.ControlField = (ControlField)_BitStream.ReadByte(3); switch (reply.ControlField) { case ControlField.AdsbDeviceTransmittingIcao24: case ControlField.AdsbRebroadcastOfExtendedSquitter: ExtractAircraftAddress(reply); ExtractExtendedSquitterMessage(reply); break; case ControlField.AdsbDeviceNotTransmittingIcao24: reply.NonIcao24Address = (int)_BitStream.ReadUInt32(24); ExtractExtendedSquitterMessage(reply); break; default: reply.ExtendedSquitterSupplementaryMessage = ReadBytes(10); break; } ExtractParityInterrogator(reply); }
private void ExtractVerticalStatus(ModeSMessage reply) { reply.VerticalStatus = (VerticalStatus)_BitStream.ReadByte(1); }
private void ExtractUtilityMessage(ModeSMessage reply) { reply.UtilityMessage = _BitStream.ReadByte(6); }
private void ExtractSensitivityLevel(ModeSMessage reply) { reply.SensitivityLevel = _BitStream.ReadByte(3); }
private void ExtractReplyInformation(ModeSMessage reply) { reply.ReplyInformation = _BitStream.ReadByte(4); }
private void ExtractParityInterrogator(ModeSMessage reply) { reply.ParityInterrogatorIdentifier = (int)_BitStream.ReadUInt32(24); }
private void ExtractFlightStatus(ModeSMessage reply) { reply.FlightStatus = (FlightStatus)_BitStream.ReadByte(3); }
private void ExtractExtendedSquitterMessage(ModeSMessage reply) { reply.ExtendedSquitterMessage = ReadBytes(7); }
private void ExtractDownlinkRequest(ModeSMessage reply) { reply.DownlinkRequest = _BitStream.ReadByte(5); }
/// <summary> /// Creates a new object. /// </summary> /// <param name="modeSMessage"></param> public AdsbMessage(ModeSMessage modeSMessage) { ModeSMessage = modeSMessage; }
public PointLatLngAlt pllalocal(ModeSMessage newmsg) { if (newmsg == null) return PointLatLngAlt.Zero; int num = 131072; double denominator = (newmsg.OddFormat ? 6.101694915254237 : 6.0); double num3 = 360.0; double latitude = reflat; double num5 = ((double)newmsg.lat) / ((double)num); double num6 = Math.Floor((double)(latitude / denominator)) + Math.Floor((double)((0.5 + (this.modulo(latitude, denominator) / denominator)) - num5)); double lat = denominator * (num6 + num5); int num7 = this.NL(newmsg.lat) - (newmsg.OddFormat ? 1 : 0); double numerator = reflng; double num9 = (num7 == 0) ? num3 : (num3 / ((double)num7)); double num10 = ((double)newmsg.lng) / ((double)num); double num11 = Math.Floor((double)(numerator / num9)) + Math.Floor((double)((0.5 + (this.modulo(numerator, num9) / num9)) - num10)); double lng = num9 * (num11 + num10); return new PointLatLngAlt(lat,lng); }
/// <summary> /// See interface docs. /// </summary> /// <param name="rawMessage"></param> /// <param name="start"></param> /// <param name="signalLevel"></param> /// <param name="isMlat"></param> /// <returns></returns> public ModeSMessage Translate(byte[] rawMessage, int start, int?signalLevel, bool isMlat) { if (Statistics == null) { throw new InvalidOperationException("Statistics must be provided before Translate can do any work"); } ModeSMessage result = null; var messageLength = rawMessage == null ? 0 : rawMessage.Length - start; if (messageLength > 6) { _BitStream.Initialise(rawMessage); _BitStream.Skip(start * 8); var downlinkFormatValue = _BitStream.ReadByte(5); if (downlinkFormatValue >= 24) { downlinkFormatValue = 24; _BitStream.Skip(-3); } bool isLongFrame = true; switch (downlinkFormatValue) { case 16: case 17: case 18: case 19: case 20: case 21: case 24: if (messageLength > 13) { result = new ModeSMessage(); } break; default: isLongFrame = false; result = new ModeSMessage(); break; } if (result != null) { result.SignalLevel = signalLevel; result.IsMlat = isMlat; result.DownlinkFormat = (DownlinkFormat)downlinkFormatValue; switch (result.DownlinkFormat) { case DownlinkFormat.ShortAirToAirSurveillance: DecodeShortAirToAirSurveillance(result); break; // DF0 case DownlinkFormat.SurveillanceAltitudeReply: DecodeSurveillanceAltitudeReply(result); break; // DF4 case DownlinkFormat.SurveillanceIdentityReply: DecodeSurveillanceIdentityReply(result); break; // DF5 case DownlinkFormat.AllCallReply: DecodeAllCallReply(result); break; // DF11 case DownlinkFormat.LongAirToAirSurveillance: DecodeLongAirToAirSurveillance(result); break; // DF16 case DownlinkFormat.ExtendedSquitter: DecodeExtendedSquitter(result); break; // DF17 case DownlinkFormat.ExtendedSquitterNonTransponder: DecodeExtendedSquitterNonTransponder(result); break; // DF18 case DownlinkFormat.MilitaryExtendedSquitter: DecodeMilitaryExtendedSquitter(result); break; // DF19 case DownlinkFormat.CommBAltitudeReply: DecodeCommBAltitudeReply(result); break; // DF20 case DownlinkFormat.CommBIdentityReply: DecodeCommBIdentityReply(result); break; // DF21 case DownlinkFormat.CommD: DecodeCommD(result); break; // DF24 } if (Statistics != null) { Statistics.Lock(r => { ++r.ModeSMessagesReceived; ++r.ModeSDFStatistics[(int)result.DownlinkFormat].MessagesReceived; if (isLongFrame) { ++r.ModeSLongFrameMessagesReceived; } else { ++r.ModeSShortFrameMessagesReceived; } }); } } } return(result); }
public void TestInitialise() { _Message = new ModeSMessage(); }
/// <summary> /// Decodes the fields from an all-call reply (DF = 11). /// </summary> /// <param name="reply"></param> private void DecodeAllCallReply(ModeSMessage reply) { ExtractCapability(reply); ExtractAircraftAddress(reply); ExtractParityInterrogator(reply); }
private void ExtractIdentity(ModeSMessage reply) { var bits = (short)_BitStream.ReadUInt16(13); reply.Identity = ModeATranslator.DecodeModeA(bits); }
private void ExtractAircraftAddress(ModeSMessage reply) { reply.Icao24 = (int)_BitStream.ReadUInt32(24); }
/// <summary> /// AVR ASCii Format Input /// </summary> /// <param name="avrline"></param> /// <returns></returns> public static Plane ReadMessage(string avrline) { if (!avrline.StartsWith("*")) { return(null); } log.Debug(avrline); avrline = avrline.Trim().TrimEnd(';'); ModeSMessage adsbmess = new ModeSMessage(); byte[] data = ConvertHexStringToByteArray(avrline.TrimStart('*')); if (data.Length < 13) { return(null); } adsbmess.DF = (byte)(data[0] >> 3); // 5 adsbmess.CA = (byte)(data[0] & 7); // 3 // aircraft icao adsbmess.AA = (uint)((data[1] << 16) + (data[2] << 8) + (data[3])); // 24 Array.Copy(data, 4, adsbmess.adsbdata, 0, 7); // 56 bytes // paraity adsbmess.PI = (uint)((data[11] << 16) + (data[12] << 8) + (data[13])); // 24 adsbmess.recvtime = DateTime.Now; // check parity Crc32ModeS crc = new Crc32ModeS(); byte[] pidata = crc.ComputeChecksumBytes(data, 0, data.Length - 3, false); if (adsbmess.PI != ((pidata[0] << 16) + (pidata[1] << 8) + pidata[2])) { Console.WriteLine("Parity Fail"); return(null); } // create the plane id string planeid = adsbmess.AA.ToString("X5"); if (!Planes.ContainsKey(planeid)) { Planes[planeid] = new Plane() { ID = planeid } } ; if (adsbmess.DF == 17 && (adsbmess.TypeCode >= 9 && adsbmess.TypeCode <= 18) || (adsbmess.TypeCode >= 0x14 && adsbmess.TypeCode <= 0x16) ) // airbornepos { // odd if (adsbmess.Fcprformat) { ((Plane)Planes[adsbmess.AA.ToString("X5")]).llaodd = adsbmess; //Console.WriteLine("adsb " + planeid + " type " + adsbmess.DF + " odd"); } else // even { ((Plane)Planes[adsbmess.AA.ToString("X5")]).llaeven = adsbmess; //Console.WriteLine("adsb " + planeid + " type " + adsbmess.DF + " even"); } } else if (adsbmess.DF == 17 && adsbmess.TypeCode >= 1 && adsbmess.TypeCode <= 4) // ident { StringBuilder builder = new StringBuilder(); int count = 8; for (int i = 0; i < count; i++) { char ch = '\0'; byte[] char1 = adsbmess.getbits(adsbmess.adsbdata, 7 + i * 6, 6); byte num2 = char1[0]; if ((num2 > 0) && (num2 < 0x1b)) { ch = (char)(0x41 + (num2 - 1)); } else if (num2 == 0x20) { ch = ' '; } else if ((num2 > 0x2f) && (num2 < 0x3a)) { ch = (char)(0x30 + (num2 - 0x30)); } if (ch != '\0') { builder.Append(ch); } } adsbmess.Ident = builder.ToString(); //Console.WriteLine("Ident " + builder.ToString()); } else if (adsbmess.DF == 17 && adsbmess.TypeCode == 0x13) // velocity { int subtype = adsbmess.adsbdata[0] & 7; int accuracy = (adsbmess.adsbdata[1] >> 3) & 15; switch (subtype) { case 3: case 4: bool headingstatus = ((adsbmess.adsbdata[1] >> 2) & 1) > 0; if (headingstatus) { ushort head = (ushort)(((adsbmess.adsbdata[1] & 3) << 8) + adsbmess.adsbdata[2]); double heading = head * 0.3515625; ((Plane)Planes[adsbmess.AA.ToString("X5")]).heading = heading; } break; case 1: case 2: default: bool westvel = ((adsbmess.adsbdata[1] >> 2) & 1) > 0; int ewvel = (int)(((adsbmess.adsbdata[1] & 3) << 8) + adsbmess.adsbdata[2]); bool southvel = ((adsbmess.adsbdata[3] >> 7) & 1) > 0; int nsvel = (int)(((adsbmess.adsbdata[3] & 127) << 3) + (adsbmess.adsbdata[4] >> 5)); if (westvel) { ewvel *= -1; } if (southvel) { nsvel *= -1; } double cog = (Math.Atan2(ewvel, nsvel) * (180 / Math.PI)); Console.WriteLine("vel " + ewvel + " " + nsvel + " " + cog); ((Plane)Planes[adsbmess.AA.ToString("X5")]).heading = (cog + 360) % 360; break; } } else { Console.WriteLine("No processing type 0x" + adsbmess.TypeCode.ToString("X2") + " DF " + adsbmess.DF); } return((Plane)Planes[adsbmess.AA.ToString("X5")]); }
private void ExtractAircraftParityIdentifier(ModeSMessage reply) { reply.Icao24 = (int)_BitStream.ReadUInt32(24); }
/// <summary> /// AVR ASCii Format Input /// </summary> /// <param name="avrline"></param> /// <returns></returns> public static Plane ReadMessage(string avrline) { if (!avrline.StartsWith("*")) return null; log.Debug(avrline); avrline = avrline.Trim().TrimEnd(';'); ModeSMessage adsbmess = new ModeSMessage(); byte[] data = ConvertHexStringToByteArray(avrline.TrimStart('*')); if (data.Length < 13) return null; adsbmess.DF = (byte)(data[0] >> 3); // 5 adsbmess.CA = (byte)(data[0] & 7); // 3 // aircraft icao adsbmess.AA = (uint)((data[1] << 16) + (data[2] << 8) +(data[3])); // 24 Array.Copy(data, 4, adsbmess.adsbdata, 0, 7); // 56 bytes // paraity adsbmess.PI = (uint)((data[11] << 16) + (data[12] << 8) + (data[13])); // 24 adsbmess.recvtime = DateTime.Now; // check parity Crc32ModeS crc = new Crc32ModeS(); byte[] pidata = crc.ComputeChecksumBytes(data, 0, data.Length - 3, false); if (adsbmess.PI != ((pidata[0] << 16) + (pidata[1] << 8) + pidata[2])) { Console.WriteLine("Parity Fail"); return null; } // create the plane id string planeid = adsbmess.AA.ToString("X5"); if (!Planes.ContainsKey(planeid)) Planes[planeid] = new Plane() { ID = planeid }; if (adsbmess.DF == 17 && (adsbmess.TypeCode >= 9 && adsbmess.TypeCode <= 18) || (adsbmess.TypeCode >= 0x14 && adsbmess.TypeCode <= 0x16) ) // airbornepos { // odd if (adsbmess.Fcprformat) { ((Plane)Planes[adsbmess.AA.ToString("X5")]).llaodd = adsbmess; //Console.WriteLine("adsb " + planeid + " type " + adsbmess.DF + " odd"); } else // even { ((Plane)Planes[adsbmess.AA.ToString("X5")]).llaeven = adsbmess; //Console.WriteLine("adsb " + planeid + " type " + adsbmess.DF + " even"); } } else if (adsbmess.DF == 17 && adsbmess.TypeCode >= 1 && adsbmess.TypeCode <= 4) // ident { StringBuilder builder = new StringBuilder(); int count = 8; for (int i = 0; i < count; i++) { char ch = '\0'; byte[] char1 = adsbmess.getbits(adsbmess.adsbdata, 7 + i * 6, 6); byte num2 = char1[0]; if ((num2 > 0) && (num2 < 0x1b)) { ch = (char)(0x41 + (num2 - 1)); } else if (num2 == 0x20) { ch = ' '; } else if ((num2 > 0x2f) && (num2 < 0x3a)) { ch = (char)(0x30 + (num2 - 0x30)); } if (ch != '\0') { builder.Append(ch); } } adsbmess.Ident = builder.ToString(); //Console.WriteLine("Ident " + builder.ToString()); } else if (adsbmess.DF == 17 && adsbmess.TypeCode == 0x13) // velocity { int subtype = adsbmess.adsbdata[0] & 7; int accuracy = (adsbmess.adsbdata[1] >> 3) & 15; switch (subtype) { case 3: case 4: bool headingstatus = ((adsbmess.adsbdata[1] >> 2) & 1) > 0; if (headingstatus) { ushort head = (ushort)(((adsbmess.adsbdata[1] & 3) << 8) + adsbmess.adsbdata[2]); double heading = head * 0.3515625; ((Plane)Planes[adsbmess.AA.ToString("X5")]).heading = heading; } break; case 1: case 2: default: bool westvel = ((adsbmess.adsbdata[1] >> 2) & 1) > 0; int ewvel = (int)(((adsbmess.adsbdata[1] & 3) << 8) + adsbmess.adsbdata[2]); bool southvel = ((adsbmess.adsbdata[3] >> 7) & 1) > 0; int nsvel = (int)(((adsbmess.adsbdata[3] & 127) << 3) + (adsbmess.adsbdata[4] >> 5)); if (westvel) ewvel *= -1; if (southvel) nsvel *= -1; double cog = (Math.Atan2(ewvel, nsvel) * (180 / Math.PI)); Console.WriteLine("vel " + ewvel + " " + nsvel + " " + cog); ((Plane)Planes[adsbmess.AA.ToString("X5")]).heading = (cog + 360) % 360; break; } } else { Console.WriteLine("No processing type 0x" + adsbmess.TypeCode.ToString("X2") + " DF " + adsbmess.DF); } return ((Plane)Planes[adsbmess.AA.ToString("X5")]); }
private void ExtractCapability(ModeSMessage reply) { reply.Capability = (Capability)_BitStream.ReadByte(3); }