/// <summary> /// Initializes a new instance of the <see cref="Rmb"/> class. /// </summary> /// <param name="type">The message type</param> /// <param name="message">The NMEA message values.</param> public Rmb(string type, string[] message) : base(type, message) { if (message == null || message.Length < 13) { throw new ArgumentException("Invalid GPRMB", "message"); } Status = message[0] == "A" ? DataStatus.Ok : Rmb.DataStatus.Warning; double tmp; if (double.TryParse(message[1], NumberStyles.Float, CultureInfo.InvariantCulture, out tmp)) { CrossTrackError = tmp; if (message[2] == "L") //Steer left { CrossTrackError *= -1; } } else { CrossTrackError = double.NaN; } if (message[3].Length > 0) { OriginWaypointId = int.Parse(message[3], CultureInfo.InvariantCulture); } if (message[3].Length > 0) { DestinationWaypointId = int.Parse(message[4], CultureInfo.InvariantCulture); } DestinationLatitude = NmeaMessage.StringToLatitude(message[5], message[6]); DestinationLongitude = NmeaMessage.StringToLongitude(message[7], message[8]); if (double.TryParse(message[9], NumberStyles.Float, CultureInfo.InvariantCulture, out tmp)) { RangeToDestination = tmp; } else { RangeToDestination = double.NaN; } if (double.TryParse(message[10], NumberStyles.Float, CultureInfo.InvariantCulture, out tmp)) { TrueBearing = tmp; } else { TrueBearing = double.NaN; } if (double.TryParse(message[11], NumberStyles.Float, CultureInfo.InvariantCulture, out tmp)) { Velocity = tmp; } else { Velocity = double.NaN; } Arrived = message[12] == "A"; }
/// <summary> /// Initializes a new instance of the <see cref="Gga"/> class. /// </summary> /// <param name="type">The message type</param> /// <param name="message">The NMEA message values.</param> public Gga(string type, string[] message) : base(type, message) { if (message == null || message.Length < 14) { throw new ArgumentException("Invalid GPGGA", "message"); } FixTime = StringToTimeSpan(message[0]); Latitude = NmeaMessage.StringToLatitude(message[1], message[2]); Longitude = NmeaMessage.StringToLongitude(message[3], message[4]); Quality = (Gga.FixQuality) int.Parse(message[5], CultureInfo.InvariantCulture); NumberOfSatellites = int.Parse(message[6], CultureInfo.InvariantCulture); Hdop = NmeaMessage.StringToDouble(message[7]); Altitude = NmeaMessage.StringToDouble(message[8]); AltitudeUnits = message[9]; HeightOfGeoid = NmeaMessage.StringToDouble(message[10]); HeightOfGeoidUnits = message[11]; var timeInSeconds = StringToDouble(message[12]); if (!double.IsNaN(timeInSeconds)) { TimeSinceLastDgpsUpdate = TimeSpan.FromSeconds(timeInSeconds); } else { TimeSinceLastDgpsUpdate = TimeSpan.MaxValue; } if (message[13].Length > 0) { DgpsStationId = int.Parse(message[13], CultureInfo.InvariantCulture); } else { DgpsStationId = -1; } }
/// <summary> /// Initializes a new instance of the <see cref="Gll"/> class. /// </summary> /// <param name="type">The message type</param> /// <param name="message">The NMEA message values.</param> public Gll(string type, string[] message) : base(type, message) { if (message == null || message.Length < 4) { throw new ArgumentException("Invalid GPGLL", "message"); } Latitude = NmeaMessage.StringToLatitude(message[0], message[1]); Longitude = NmeaMessage.StringToLongitude(message[2], message[3]); if (message.Length >= 5) //Some older GPS doesn't broadcast fix time { FixTime = StringToTimeSpan(message[4]); } DataActive = (message.Length < 6 || message[5] == "A"); ModeIndicator = DataActive ? Mode.Autonomous : Mode.DataNotValid; if (message.Length > 6) { switch (message[6]) { case "A": ModeIndicator = Mode.Autonomous; break; case "D": ModeIndicator = Mode.DataNotValid; break; case "E": ModeIndicator = Mode.EstimatedDeadReckoning; break; case "M": ModeIndicator = Mode.Manual; break; case "S": ModeIndicator = Mode.Simulator; break; case "N": ModeIndicator = Mode.DataNotValid; break; } } }
/// <summary> /// Initializes a new instance of the <see cref="Rmc"/> class. /// </summary> /// <param name="type">The message type</param> /// <param name="message">The NMEA message values.</param> public Rmc(string type, string[] message) : base(type, message) { if (message == null || message.Length < 11) { throw new ArgumentException("Invalid GPRMC", "message"); } if (message[8].Length == 6 && message[0].Length >= 6) { FixTime = new DateTime(int.Parse(message[8].Substring(4, 2), CultureInfo.InvariantCulture) + 2000, int.Parse(message[8].Substring(2, 2), CultureInfo.InvariantCulture), int.Parse(message[8].Substring(0, 2), CultureInfo.InvariantCulture), int.Parse(message[0].Substring(0, 2), CultureInfo.InvariantCulture), int.Parse(message[0].Substring(2, 2), CultureInfo.InvariantCulture), 0, DateTimeKind.Utc).AddSeconds(double.Parse(message[0].Substring(4), CultureInfo.InvariantCulture)); } Active = (message[1] == "A"); Latitude = NmeaMessage.StringToLatitude(message[2], message[3]); Longitude = NmeaMessage.StringToLongitude(message[4], message[5]); Speed = NmeaMessage.StringToDouble(message[6]); Course = NmeaMessage.StringToDouble(message[7]); MagneticVariation = NmeaMessage.StringToDouble(message[9]); if (!double.IsNaN(MagneticVariation) && message[10] == "W") { MagneticVariation *= -1; } }
/// <summary> /// Initializes a new instance of the <see cref="Gns"/> class. /// </summary> /// <param name="type">The message type</param> /// <param name="message">The NMEA message values.</param> public Gns(string type, string[] message) : base(type, message) { if (message == null || message.Length < 12) { throw new ArgumentException("Invalid GNS", "message"); } FixTime = StringToTimeSpan(message[0]); Latitude = NmeaMessage.StringToLatitude(message[1], message[2]); Longitude = NmeaMessage.StringToLongitude(message[3], message[4]); if (message[5].Length > 0) { GpsModeIndicator = ParseModeIndicator(message[5][0]); } if (message[5].Length > 1) { GlonassModeIndicator = ParseModeIndicator(message[5][1]); } if (message[5].Length > 2) { FutureModeIndicator = message[5].Skip(2).Select(t => ParseModeIndicator(t)).ToArray(); } else { FutureModeIndicator = new Mode[] { } }; NumberOfSatellites = int.Parse(message[6], CultureInfo.InvariantCulture); Hdop = NmeaMessage.StringToDouble(message[7]); OrhometricHeight = NmeaMessage.StringToDouble(message[8]); GeoidalSeparation = NmeaMessage.StringToDouble(message[9]); var timeInSeconds = StringToDouble(message[10]); if (!double.IsNaN(timeInSeconds)) { TimeSinceLastDgpsUpdate = TimeSpan.FromSeconds(timeInSeconds); } else { TimeSinceLastDgpsUpdate = TimeSpan.MaxValue; } if (message[11].Length > 0) { DgpsStationId = message[11]; } if (message.Length > 12) { switch (message[12]) { case "S": Status = NavigationalStatus.Safe; break; case "C": Status = NavigationalStatus.Caution; break; case "U": Status = NavigationalStatus.Unsafe; break; case "V": default: Status = NavigationalStatus.NotValid; break; } } }
/// <summary> /// Parses the specified NMEA message. /// </summary> /// <param name="message">The NMEA message string.</param> /// <returns></returns> /// <exception cref="System.ArgumentException"> /// Invalid nmea message: Missing starting character '$' /// or checksum failure /// </exception> public static NmeaMessage Parse(string message) { if (string.IsNullOrEmpty(message)) { throw new ArgumentNullException("message"); } int checksum = -1; if (message[0] != '$') { throw new ArgumentException("Invalid nmea message: Missing starting character '$'"); } var idx = message.IndexOf('*'); if (idx >= 0) { checksum = Convert.ToInt32(message.Substring(idx + 1), 16); message = message.Substring(0, message.IndexOf('*')); } if (checksum > -1) { int checksumTest = 0; for (int i = 1; i < message.Length; i++) { checksumTest ^= Convert.ToByte(message[i]); } if (checksum != checksumTest) { throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Invalid nmea message: Checksum failure. Got {0:X2}, Expected {1:X2}", checksum, checksumTest)); } } string[] parts = message.Split(new char[] { ',' }); string MessageType = parts[0].Substring(1); string[] MessageParts = parts.Skip(1).ToArray(); if (messageTypes == null) { LoadResponseTypes(); } NmeaMessage msg = null; if (messageTypes.ContainsKey(MessageType)) { msg = (NmeaMessage)messageTypes[MessageType].Invoke(new object[] { }); } else { msg = new UnknownMessage(); } msg.MessageType = MessageType; msg.MessageParts = MessageParts; msg.OnLoadMessage(MessageParts); return(msg); }
/// <summary> /// Initializes a new instance of the <see cref="Vtg"/> class. /// </summary> /// <param name="type">The message type</param> /// <param name="message">The NMEA message values.</param> public Vtg(string type, string[] message) : base(type, message) { if (message == null || message.Length < 7) { throw new ArgumentException("Invalid Gpvtg", "message"); } TrueCourseOverGround = NmeaMessage.StringToDouble(message[0]); MagneticCourseOverGround = NmeaMessage.StringToDouble(message[2]); SpeedInKnots = NmeaMessage.StringToDouble(message[4]); SpeedInKph = NmeaMessage.StringToDouble(message[6]); }
/// <summary> /// Called when the message is being loaded. /// </summary> /// <param name="message">The NMEA message values.</param> protected override void OnLoadMessage(string[] message) { if (message == null || message.Length < 14) { throw new ArgumentException("Invalid GPGGA", "message"); } FixTime = StringToTimeSpan(message[0]); Validity = message[1]; Latitude = NmeaMessage.StringToLatitude(message[2], message[3]); Longitude = NmeaMessage.StringToLongitude(message[4], message[5]); Sog = Double.Parse(message[5], CultureInfo.InvariantCulture); Cog = Double.Parse(message[6], CultureInfo.InvariantCulture); DateOfFix = message[7]; }
/// <summary> /// Called when the message is being loaded. /// </summary> /// <param name="message">The NMEA message values.</param> protected override void OnLoadMessage(string[] message) { if (message == null || message.Length < 4) { throw new ArgumentException("Invalid GPGLL", "message"); } Latitude = NmeaMessage.StringToLatitude(message[0], message[1]); Longitude = NmeaMessage.StringToLongitude(message[2], message[3]); if (message.Length >= 5) //Some older GPS doesn't broadcast fix time { FixTime = StringToTimeSpan(message[4]); } DataActive = (message.Length < 6 || message[5] == "A"); }
/// <summary> /// Initializes a new instance of the <see cref="Gst"/> class. /// </summary> /// <param name="type">The message type</param> /// <param name="message">The NMEA message values.</param> public Gst(string type, string[] message) : base(type, message) { if (message == null || message.Length < 8) { throw new ArgumentException("Invalid GPGST", "message"); } FixTime = StringToTimeSpan(message[0]); Rms = NmeaMessage.StringToDouble(message[1]); SemiMajorError = NmeaMessage.StringToDouble(message[2]); SemiMinorError = NmeaMessage.StringToDouble(message[3]); ErrorOrientation = NmeaMessage.StringToDouble(message[4]); SigmaLatitudeError = NmeaMessage.StringToDouble(message[5]); SigmaLongitudeError = NmeaMessage.StringToDouble(message[6]); SigmaHeightError = NmeaMessage.StringToDouble(message[7]); }
private void OnMessageReceived(Nmea.NmeaMessage msg) { var args = new NmeaMessageReceivedEventArgs(msg); var multi = msg as IMultiPartMessage; if (multi != null) { args.IsMultipart = true; if (MultiPartMessageCache.ContainsKey(msg.MessageType)) { var dic = MultiPartMessageCache[msg.MessageType]; if (dic.ContainsKey(multi.MessageNumber - 1) && !dic.ContainsKey(multi.MessageNumber)) { dic[multi.MessageNumber] = msg; } else //Something is out of order. Clear cache { MultiPartMessageCache.Remove(msg.MessageType); } } else if (multi.MessageNumber == 1) { MultiPartMessageCache[msg.MessageType] = new Dictionary <int, Nmea.NmeaMessage>(multi.TotalMessages); MultiPartMessageCache[msg.MessageType][1] = msg; } if (MultiPartMessageCache.ContainsKey(msg.MessageType)) { var dic = MultiPartMessageCache[msg.MessageType]; if (dic.Count == multi.TotalMessages) //We have a full list { MultiPartMessageCache.Remove(msg.MessageType); args.MessageParts = dic.Values.ToArray(); } } } if (MessageReceived != null) { MessageReceived(this, args); } }
private void OnMessageReceived(Nmea.NmeaMessage msg) { if (msg == null) { return; } Nmea.NmeaMessage[]? messageParts = null; if (msg is IMultiPartMessage multi) { string messageType = msg.MessageType.Substring(2); //We don't care about the two first characters. Ie GPGSV, GLGSV, GAGSV etc are all part of the same multi-part message if (MultiPartMessageCache.ContainsKey(messageType)) { var dic = MultiPartMessageCache[messageType]; if (dic.ContainsKey(multi.MessageNumber - 1) && !dic.ContainsKey(multi.MessageNumber)) { dic[multi.MessageNumber] = msg; } else //Something is out of order. Clear cache { MultiPartMessageCache.Remove(messageType); } } else if (multi.MessageNumber == 1) { MultiPartMessageCache[messageType] = new Dictionary <int, Nmea.NmeaMessage>(multi.TotalMessages); MultiPartMessageCache[messageType][1] = msg; } if (MultiPartMessageCache.ContainsKey(messageType)) { var dic = MultiPartMessageCache[messageType]; if (dic.Count == multi.TotalMessages) //We have a full list { MultiPartMessageCache.Remove(messageType); messageParts = dic.Values.ToArray(); } } } MessageReceived?.Invoke(this, new NmeaMessageReceivedEventArgs(msg, messageParts)); }
internal NmeaMessageReceivedEventArgs(Nmea.NmeaMessage message) { Message = message; }
internal NmeaMessageReceivedEventArgs(Nmea.NmeaMessage message, IReadOnlyList <Nmea.NmeaMessage>?messageParts) { Message = message; MessageParts = messageParts; }