/// <summary> /// Date and time message (ZDA). This should not normally need the last time as argument, because it defines it. /// </summary> public RoutePart(TalkerId talkerId, IEnumerable <string> fields, DateTimeOffset time) : base(talkerId, Id, time) { IEnumerator <string> field = fields.GetEnumerator(); RouteName = string.Empty; int?numberOfSequences = ReadInt(field); int?numberOfSequence = ReadInt(field); string sentenceMode = ReadString(field); string routeName = ReadString(field); // SentenceMode "w" not yet supported if (numberOfSequences.HasValue && numberOfSequence.HasValue && sentenceMode == "c") { Valid = true; RouteName = routeName; TotalSequences = numberOfSequences.Value; Sequence = numberOfSequence.Value; WaypointNames = new List <string>(); while (field.MoveNext()) { WaypointNames.Add(field.Current); } } else { // Empty list WaypointNames = new List <string>(); TotalSequences = 1; Sequence = 1; } }
/// <summary> /// Date and time message (ZDA). This should not normally need the last time as argument, because it defines it. /// </summary> public CrossTrackError(TalkerId talkerId, IEnumerable <string> fields, DateTimeOffset time) : base(talkerId, Id, time) { IEnumerator <string> field = fields.GetEnumerator(); string status1 = ReadString(field); string status2 = ReadString(field); double?distance = ReadValue(field); string direction = ReadString(field); string unit = ReadString(field); if (status1 == "A" && status2 == "A" && distance.HasValue && (direction == "L" || direction == "R") && unit == "N") { Distance = Length.FromNauticalMiles(distance.Value); if (direction == "R") { Distance = Distance * -1; } Valid = true; } else { Distance = Length.Zero; Valid = false; } }
/// <summary> /// Date and time message (ZDA). This should not normally need the last time as argument, because it defines it. /// </summary> public Waypoint(TalkerId talkerId, IEnumerable <string> fields, DateTimeOffset time) : base(talkerId, Id, time) { IEnumerator <string> field = fields.GetEnumerator(); Position = new GeographicPosition(); Name = string.Empty; double? wayPointLatitude = ReadValue(field); CardinalDirection?wayPointHemisphere = (CardinalDirection?)ReadChar(field); double? wayPointLongitude = ReadValue(field); CardinalDirection?wayPointDirection = (CardinalDirection?)ReadChar(field); string waypointName = ReadString(field); if (wayPointLatitude.HasValue && wayPointLongitude.HasValue) { double?latitude = RecommendedMinimumNavigationInformation.Nmea0183ToDegrees(wayPointLatitude, wayPointHemisphere); double?longitude = RecommendedMinimumNavigationInformation.Nmea0183ToDegrees(wayPointLongitude, wayPointDirection); if (latitude.HasValue && longitude.HasValue) { Position = new GeographicPosition(latitude.Value, longitude.Value, 0); Valid = true; } Name = waypointName; } }
/// <summary> /// Creates a VTG sentence from decoded fields /// </summary> /// <param name="talkerId">Talker Id</param> /// <param name="fields">List of fields</param> /// <param name="time">Time this message was valid</param> public TrackMadeGood(TalkerId talkerId, IEnumerable <string> fields, DateTimeOffset time) : base(talkerId, Id, time) { IEnumerator <string> field = fields.GetEnumerator(); double?courseOverGroundTrue = ReadValue(field); string reference = ReadString(field) ?? string.Empty; double?courseOverGroundMagnetic = ReadValue(field); string reference2 = ReadString(field) ?? string.Empty; double?speedKnots = ReadValue(field); string reference3 = ReadString(field) ?? string.Empty; // The HDT sentence must have a "T" (True) reference, otherwise something is fishy if (reference == "T" && courseOverGroundTrue.HasValue) { CourseOverGroundTrue = Angle.FromDegrees(courseOverGroundTrue.Value); } if (reference2 == "M" && courseOverGroundMagnetic.HasValue) { CourseOverGroundMagnetic = Angle.FromDegrees(courseOverGroundMagnetic.Value); } if (reference3 == "N" && speedKnots.HasValue) { Speed = Speed.FromKnots(speedKnots.Value); } // At least these should be set Valid = courseOverGroundTrue.HasValue && speedKnots.HasValue; }
internal Talker(TalkerId talkerId) { switch (talkerId) { case TalkerId.AB: Value = Talkers.BaseAIS; break; case TalkerId.AD: Value = Talkers.DependentAISBase; break; case TalkerId.AI: Value = Talkers.MobileAIS; break; case TalkerId.AN: Value = Talkers.AidToNavigation; break; case TalkerId.AR: Value = Talkers.Receiving; break; case TalkerId.AS: Value = Talkers.LimitedBase; break; case TalkerId.AT: Value = Talkers.Transmitting; break; case TalkerId.AX: Value = Talkers.Repeater; break; case TalkerId.BS: Value = Talkers.Deprecated; break; case TalkerId.SA: Value = Talkers.PhysicalStore; break; default: Value = Talkers.Undefined; break; } }
/// <summary> /// Decode a message /// </summary> public WindDirectionWithRespectToNorth(TalkerId talkerId, IEnumerable <string> fields, DateTimeOffset time) : base(talkerId, Id, time) { IEnumerator <string> field = fields.GetEnumerator(); double?windDirectionTrue = ReadValue(field); string referenceT = ReadString(field) ?? string.Empty; double?windDirectionMagnetic = ReadValue(field); string referenceM = ReadString(field) ?? string.Empty; double?windSpeedKnots = ReadValue(field); string referenceN = ReadString(field) ?? string.Empty; double?windSpeedMetersPerSecond = ReadValue(field); string referenceMeters = ReadString(field) ?? string.Empty; if (windDirectionTrue.HasValue && referenceT == "T") { TrueWindDirection = Angle.FromDegrees(windDirectionTrue.Value); } if (windDirectionMagnetic.HasValue && referenceM == "M") { MagneticWindDirection = Angle.FromDegrees(windDirectionMagnetic.Value); } if (windSpeedKnots.HasValue && referenceN == "N") { WindSpeed = Speed.FromKnots(windSpeedKnots.Value); } else if (windSpeedMetersPerSecond.HasValue && referenceMeters == "M") { WindSpeed = Speed.FromMetersPerSecond(windSpeedMetersPerSecond.Value); } Valid = true; }
/// <summary> /// Internal constructor from NMEA string /// </summary> public EngineRevolutions(TalkerId talkerId, IEnumerable <string> fields, DateTimeOffset time) : base(talkerId, Id, time) { IEnumerator <string> field = fields.GetEnumerator(); string source = ReadString(field); int? engineNo = ReadInt(field); double?rpm = ReadValue(field); double?pitch = ReadValue(field); string status = ReadString(field); if (source == "S") { RotationSource = RotationSource.Shaft; } else if (source == "E") { RotationSource = RotationSource.Engine; } else { RotationSource = RotationSource.Unknown; } if (engineNo.HasValue) { EngineNumber = engineNo.Value; } else { EngineNumber = 1; } if (rpm.HasValue) { RotationalSpeed = RotationalSpeed.FromRevolutionsPerMinute(rpm.Value); } else { RotationalSpeed = RotationalSpeed.Zero; } if (pitch.HasValue) { PropellerPitch = Ratio.FromPercent(pitch.Value); } if (rpm.HasValue && status == "A") { Valid = true; } else { Valid = false; } }
/// <summary> /// Date and time message (ZDA). This should not normally need the last time as argument, because it defines it. /// </summary> public WindSpeedAndAngle(TalkerId talkerId, IEnumerable <string> fields, DateTimeOffset time) : base(talkerId, Id, time) { IEnumerator <string> field = fields.GetEnumerator(); double?angle = ReadValue(field); string reference = ReadString(field) ?? string.Empty; double?speed = ReadValue(field); string unit = ReadString(field) ?? string.Empty; string status = ReadString(field) ?? string.Empty; if (status == "A" && angle.HasValue && speed.HasValue) { Angle = Angle.FromDegrees(angle.Value); if (unit == "N") { Speed = Speed.FromKnots(speed.Value); SpeedUnit = unit; } else if (unit == "M") { Speed = Speed.FromMetersPerSecond(speed.Value); SpeedUnit = unit; } else { Speed = Speed.FromMetersPerSecond(0); SpeedUnit = "M"; } if (reference == "T") { Relative = false; Angle = Angle.Normalize(true); } else { // Default, since that's what the actual wind instrument delivers Relative = true; // Relative angles are +/- 180 Angle = Angle.Normalize(false); } Valid = true; } else { Angle = Angle.Zero; Speed = Speed.Zero; SpeedUnit = string.Empty; Valid = false; } }
/// <summary> /// Internal ctor /// </summary> public BearingAndDistanceToWayPoint(TalkerId talkerId, IEnumerable <string> fields, DateTimeOffset time) : base(talkerId, Id, time) { IEnumerator <string> field = fields.GetEnumerator(); string timeString = ReadString(field); DateTimeOffset now = ParseDateTime(time, timeString); DateTime = now; NextWayPointName = string.Empty; NextWayPoint = new GeographicPosition(); double? nextWayPointLatitude = ReadValue(field); CardinalDirection?nextWayPointHemisphere = (CardinalDirection?)ReadChar(field); double? nextWayPointLongitude = ReadValue(field); CardinalDirection?nextWayPointDirection = (CardinalDirection?)ReadChar(field); double? bearingTrue = ReadValue(field); string bearingTrueIdentifier = ReadString(field); double? bearingMagnetic = ReadValue(field); string bearingMagneticIdentifier = ReadString(field); double? distance = ReadValue(field); string nm = ReadString(field); string wayPointName = ReadString(field); if (nextWayPointLongitude.HasValue && nextWayPointLatitude.HasValue) { Valid = true; double?latitude = RecommendedMinimumNavigationInformation.Nmea0183ToDegrees(nextWayPointLatitude, nextWayPointHemisphere); double?longitude = RecommendedMinimumNavigationInformation.Nmea0183ToDegrees(nextWayPointLongitude, nextWayPointDirection); if (latitude.HasValue && longitude.HasValue) { NextWayPoint = new GeographicPosition(latitude.Value, longitude.Value, 0); } NextWayPointName = wayPointName; if (bearingTrue.HasValue && bearingTrueIdentifier == "T") { BearingTrueToWayPoint = Angle.FromDegrees(bearingTrue.Value); } if (bearingMagnetic.HasValue && bearingMagneticIdentifier == "M") { BearingMagneticToWayPoint = Angle.FromDegrees(bearingMagnetic.Value); } if (distance.HasValue && nm == "N") { DistanceToWayPoint = Length.FromNauticalMiles(distance.Value); } } }
/// <summary> /// Date and time message (ZDA). This should not normally need the last time as argument, because it defines it. /// </summary> public TimeDate(TalkerId talkerId, IEnumerable <string> fields, DateTimeOffset time) : base(talkerId, Id, time) { IEnumerator <string> field = fields.GetEnumerator(); string timeString = ReadString(field); TimeSpan?localTimeOfDay = null; if (!string.IsNullOrWhiteSpace(timeString)) { // Can't use the base class methods here, because we just shouldn't rely on the input variable "today" here, as this message defines the date int hour = int.Parse(timeString.Substring(0, 2), CultureInfo.InvariantCulture); int minute = int.Parse(timeString.Substring(2, 2), CultureInfo.InvariantCulture); int seconds = int.Parse(timeString.Substring(4, 2), CultureInfo.InvariantCulture); double millis = double.Parse("0" + timeString.Substring(6), CultureInfo.InvariantCulture) * 1000; localTimeOfDay = new TimeSpan(0, hour, minute, seconds, (int)millis); } double year = ReadValue(field) ?? time.Year; double month = ReadValue(field) ?? time.Month; double day = ReadValue(field) ?? time.Day; // Offset hours and minutes (last two fields, optional and usually 0). Some sources say these fields are first, but that's apparently wrong double offset = ReadValue(field) ?? 0.0; offset += (ReadValue(field) ?? 0.0) / 60; // Some sources say the parameter order is day-month-year, some say it shall be year-month-day. Luckily, the cases are easy to distinguish, // since the year is always given as 4-digit number if (day > 2000) { double ytemp = day; day = year; year = ytemp; ReverseDateFormat = true; // If the input format is exchanged, we by default send the message out the same way } // These may be undefined or zero if the GPS receiver is not receiving valid satellite data (i.e. the receiver works, but there's no antenna connected) if (localTimeOfDay.HasValue) { DateTimeOffset t = new DateTimeOffset((int)year, (int)month, (int)day, localTimeOfDay.Value.Hours, localTimeOfDay.Value.Minutes, localTimeOfDay.Value.Seconds, localTimeOfDay.Value.Milliseconds, gregorianCalendar, TimeSpan.Zero); LocalTimeOffset = TimeSpan.FromHours(offset); DateTime = t; Valid = true; } else { // Set the reception time anyway, but tell clients that this was not a complete ZDA message Valid = false; LocalTimeOffset = TimeSpan.Zero; DateTime = time; } }
/// <summary> /// Date and time message (ZDA). This should not normally need the last time as argument, because it defines it. /// </summary> public MeteorologicalComposite(TalkerId talkerId, IEnumerable <string> fields, DateTimeOffset time) : base(talkerId, Id, time) { IEnumerator <string> field = fields.GetEnumerator(); double?baroInchesMercury = ReadValue(field); string referenceI = ReadString(field) ?? string.Empty; double?baroBars = ReadValue(field); string referenceB = ReadString(field) ?? string.Empty; double?airTemp = ReadValue(field); string referenceAir = ReadString(field) ?? string.Empty; double?waterTemp = ReadValue(field); string referenceWater = ReadString(field) ?? string.Empty; double?relHumidity = ReadValue(field); ReadValue(field); // Absolute humidity (ignored, since meaning unclear) double?dewPoint = ReadValue(field); string referenceDewPoint = ReadString(field) ?? string.Empty; if (baroBars.HasValue && referenceB == "B") { BarometricPressure = Pressure.FromHectopascals(baroBars.Value * 1000); } else if (baroInchesMercury.HasValue && referenceI == "I") { BarometricPressure = Pressure.FromInchesOfMercury(baroInchesMercury.Value); } if (airTemp.HasValue && referenceAir == "C") { AirTemperature = Temperature.FromDegreesCelsius(airTemp.Value); } if (waterTemp.HasValue && referenceWater == "C") { WaterTemperature = Temperature.FromDegreesCelsius(waterTemp.Value); } if (relHumidity.HasValue) { RelativeHumidity = UnitsNet.RelativeHumidity.FromPercent(relHumidity.Value); } if (dewPoint.HasValue && referenceDewPoint == "C") { DewPoint = Temperature.FromDegreesCelsius(dewPoint.Value); } // Note: The remaining fields are about wind speed/direction. These are not parsed here, use MWV sentence instead Valid = true; }
/// <summary> /// Magnetic heading message /// </summary> public HeadingAndDeclination(TalkerId talkerId, IEnumerable <string> fields, DateTimeOffset time) : base(talkerId, Id, time) { IEnumerator <string> field = fields.GetEnumerator(); double?heading = ReadValue(field); double?deviation = ReadValue(field); string deviationDirection = ReadString(field); double?magVar = ReadValue(field); string magVarDirection = ReadString(field); string reference = ReadString(field) ?? string.Empty; Valid = false; if (heading.HasValue) { HeadingTrue = Angle.FromDegrees(heading.Value); // This one needs to be there, the others are optional Valid = true; } if (deviation.HasValue) { if (deviationDirection == "E") { Deviation = Angle.FromDegrees(deviation.Value); } else { Deviation = Angle.FromDegrees(deviation.Value * -1); } } if (magVar.HasValue) { if (magVarDirection == "E") { Declination = Angle.FromDegrees(magVar.Value); } else { Declination = Angle.FromDegrees(magVar.Value * -1); } } }
/// <summary> /// Magnetic heading message /// </summary> public HeadingMagnetic(TalkerId talkerId, IEnumerable <string> fields, DateTimeOffset time) : base(talkerId, Id, time) { IEnumerator <string> field = fields.GetEnumerator(); double?angle = ReadValue(field); string reference = ReadString(field) ?? string.Empty; // The HDM sentence must have a "M" (Magnetic) reference, otherwise something is fishy if (reference == "M" && angle.HasValue) { Angle = Angle.FromDegrees(angle.Value); Valid = true; } else { Angle = Angle.Zero; Valid = false; } }
/// <summary> /// Date and time message (ZDA). This should not normally need the last time as argument, because it defines it. /// </summary> public SatellitesInView(TalkerId talkerId, IEnumerable <string> fields, DateTimeOffset time) : base(talkerId, Id, time) { IEnumerator <string> field = fields.GetEnumerator(); Satellites = new List <SatelliteInfo>(); int?totalSequences = ReadInt(field); int?currentSequence = ReadInt(field); int?totalSatellites = ReadInt(field); if (!totalSequences.HasValue || !currentSequence.HasValue || !totalSatellites.HasValue) { TotalSequences = 0; Sequence = 0; Valid = false; return; } TotalSequences = totalSequences.Value; Sequence = currentSequence.Value; TotalSatellites = totalSatellites.Value; string id = ReadString(field); while (!string.IsNullOrWhiteSpace(id)) { double? elevation = ReadValue(field); double? azimuth = ReadValue(field); double? snr = ReadValue(field); SatelliteInfo info = new SatelliteInfo(id) { Azimuth = azimuth.HasValue ? Angle.FromDegrees(azimuth.Value) : null, Elevation = elevation.HasValue ? Angle.FromDegrees(elevation.Value) : null, Snr = snr }; Satellites.Add(info); id = ReadString(field); } Valid = true; }
/// <summary> /// Date and time message (ZDA). This should not normally need the last time as argument, because it defines it. /// </summary> public DepthBelowSurface(TalkerId talkerId, IEnumerable <string> fields, DateTimeOffset time) : base(talkerId, Id, time) { IEnumerator <string> field = fields.GetEnumerator(); string feet = ReadString(field); string feetUnit = ReadString(field); double?meters = ReadValue(field); string metersUnit = ReadString(field); if (metersUnit == "M" && meters.HasValue) { Depth = Length.FromMeters(meters.Value); Valid = true; } else { Depth = Length.Zero; Valid = false; } }
/// <summary> /// Date and time message (ZDA). This should not normally need the last time as argument, because it defines it. /// </summary> public WaterSpeedAndAngle(TalkerId talkerId, IEnumerable <string> fields, DateTimeOffset time) : base(talkerId, Id, time) { IEnumerator <string> field = fields.GetEnumerator(); double?angleTrue = ReadValue(field); string referenceT = ReadString(field) ?? string.Empty; double?angleMagnetic = ReadValue(field); string referenceM = ReadString(field) ?? string.Empty; double?speed = ReadValue(field); string speedUnit = ReadString(field) ?? string.Empty; Valid = false; HeadingTrue = null; HeadingMagnetic = null; if (referenceT == "T" && angleTrue.HasValue) { HeadingTrue = Angle.FromDegrees(angleTrue.Value); } if (referenceM == "M" && angleMagnetic.HasValue) { HeadingMagnetic = Angle.FromDegrees(angleMagnetic.Value); } if (speedUnit == "N" && speed.HasValue) { Speed = Speed.FromKnots(speed.Value); } // The other information can be obtained by other messages, the water speed is the only we really need this message if (speed.HasValue) { Valid = true; } }
/// <summary> /// Date and time message (ZDA). This should not normally need the last time as argument, because it defines it. /// </summary> public BearingOriginToDestination(TalkerId talkerId, IEnumerable <string> fields, DateTimeOffset time) : base(talkerId, Id, time) { IEnumerator <string> field = fields.GetEnumerator(); OriginName = string.Empty; DestinationName = string.Empty; double?bearingTrue = ReadValue(field); string referenceTrue = ReadString(field); double?bearingMagnetic = ReadValue(field); string referenceMagnetic = ReadString(field); string waypointToName = ReadString(field); string waypointFromName = ReadString(field); if (bearingTrue.HasValue && bearingMagnetic.HasValue && referenceTrue == "T" && referenceMagnetic == "M") { BearingTrue = Angle.FromDegrees(bearingTrue.Value); BearingMagnetic = Angle.FromDegrees(bearingMagnetic.Value); DestinationName = waypointToName; OriginName = waypointFromName; Valid = true; } }
/// <summary> /// See <see cref="NmeaSentence"/> for constructor usage /// </summary> public RecommendedMinimumNavigationInformation(TalkerId talkerId, IEnumerable <string> fields, DateTimeOffset time) : base(talkerId, Id, time) { IEnumerator <string> field = fields.GetEnumerator(); Position = new GeographicPosition(); string newTime = ReadString(field); NavigationStatus? status = (NavigationStatus?)ReadChar(field); double? lat = ReadValue(field); CardinalDirection?latTurn = (CardinalDirection?)ReadChar(field); double? lon = ReadValue(field); CardinalDirection?lonTurn = (CardinalDirection?)ReadChar(field); double? speed = ReadValue(field); double? track = ReadValue(field); string date = ReadString(field); DateTimeOffset dateTime; if (date.Length != 0) { dateTime = ParseDateTime(date, newTime); } else { dateTime = ParseDateTime(time, newTime); } double? mag = ReadValue(field); CardinalDirection?magTurn = (CardinalDirection?)ReadChar(field); // handle undocumented field // per spec we should not have any extra fields but NEO-M8 does have them if (field.MoveNext()) { string val = field.Current; Status2 = string.IsNullOrEmpty(val) ? (NavigationStatus?)null : (NavigationStatus?)val.FirstOrDefault(); } DateTime = dateTime; Status = status; double?latitude = Nmea0183ToDegrees(lat, latTurn); double?longitude = Nmea0183ToDegrees(lon, lonTurn); if (latitude.HasValue && longitude.HasValue) { Position = new GeographicPosition(latitude.Value, longitude.Value, 0); // If the message contains no position, it is unusable. // On the other hand, if the position is known (meaning the GPS receiver works), speed and track are known, too. Valid = true; } SpeedOverGround = Speed.FromKnots(speed.GetValueOrDefault(0)); if (track.HasValue) { TrackMadeGoodInDegreesTrue = Angle.FromDegrees(track.Value); } else { TrackMadeGoodInDegreesTrue = Angle.Zero; } if (mag.HasValue && magTurn.HasValue) { MagneticVariationInDegrees = Angle.FromDegrees(mag.Value * DirectionToSign(magTurn.Value)); } }
public void ThenTheAisTalkerIs(TalkerId talkerId) { this.Then(parser => Assert.AreEqual(talkerId, parser.AisTalker)); }
/// <summary> /// Creates an unknown sentence from a split of parameters /// </summary> public RawSentence(TalkerId talkerId, SentenceId id, IEnumerable <string> fields, DateTimeOffset time) : base(talkerId, id, time) { _fields = fields.ToArray(); Valid = true; }
/// <summary> /// See <see cref="NmeaSentence"/> for constructor usage /// </summary> public RecommendedMinimumNavToDestination(TalkerId talkerId, IEnumerable <string> fields, DateTimeOffset time) : base(talkerId, Id, time) { IEnumerator <string> field = fields.GetEnumerator(); PreviousWayPointName = string.Empty; NextWayPointName = String.Empty; NextWayPoint = new GeographicPosition(); string overallStatus = ReadString(field); double? crossTrackError = ReadValue(field); string directionToSteer = ReadString(field); string previousWayPoint = ReadString(field); string nextWayPoint = ReadString(field); double? nextWayPointLatitude = ReadValue(field); CardinalDirection?nextWayPointHemisphere = (CardinalDirection?)ReadChar(field); double? nextWayPointLongitude = ReadValue(field); CardinalDirection?nextWayPointDirection = (CardinalDirection?)ReadChar(field); double? rangeToWayPoint = ReadValue(field); double? bearing = ReadValue(field); double? approachSpeed = ReadValue(field); string arrivalStatus = ReadString(field); if (overallStatus == "A") { Valid = true; if (directionToSteer == "R") { CrossTrackError = -Length.FromNauticalMiles(crossTrackError.GetValueOrDefault(0)); } else { CrossTrackError = Length.FromNauticalMiles(crossTrackError.GetValueOrDefault(0)); } PreviousWayPointName = previousWayPoint ?? string.Empty; NextWayPointName = nextWayPoint ?? string.Empty; double?latitude = RecommendedMinimumNavigationInformation.Nmea0183ToDegrees(nextWayPointLatitude, nextWayPointHemisphere); double?longitude = RecommendedMinimumNavigationInformation.Nmea0183ToDegrees(nextWayPointLongitude, nextWayPointDirection); if (latitude.HasValue && longitude.HasValue) { NextWayPoint = new GeographicPosition(latitude.Value, longitude.Value, 0); } if (rangeToWayPoint.HasValue) { DistanceToWayPoint = Length.FromNauticalMiles(rangeToWayPoint.Value); } if (bearing.HasValue) { BearingToWayPoint = Angle.FromDegrees(bearing.Value); } if (approachSpeed.HasValue) { ApproachSpeed = Speed.FromKnots(approachSpeed.Value); } if (arrivalStatus == "A") { Arrived = true; } else { Arrived = false; } } }
/// <summary> /// Constructs an instance of this abstract class /// </summary> /// <param name="talker">The talker (sender) of this message</param> /// <param name="id">Sentence Id</param> /// <param name="time">Date/Time this message was valid (derived from last time message)</param> protected NmeaSentence(TalkerId talker, SentenceId id, DateTimeOffset time) { SentenceId = id; TalkerId = talker; DateTime = time; }