private void PublishFix(GPSFix fix, NMEASentenceType fixSource) { if (fixSource == fixTriggerSentence) { if (haveGGA && haveRMC) { // Output a combined fix if the partial fix is valid. if ((partialFix != null) && (partialFix.UTCFixTime == fix.UTCFixTime) && (fixSource != partialFixSentenceType)) { GPSFix fixRMC = fixSource == NMEASentenceType.RMC ? fix : partialFix; GPSFix fixGGA = fixSource == NMEASentenceType.GGA ? fix : partialFix; m_MostRecentGPSFix = fixGGA; m_MostRecentGPSFix.HeadingRadians = fixRMC.HeadingRadians; m_MostRecentGPSFix.SpeedEast = fixRMC.SpeedEast; m_MostRecentGPSFix.SpeedNorth = fixRMC.SpeedNorth; // Still need to calculate vertical speed. Sigh. CalculateSpeedAndHeading(m_MostRecentGPSFix, true); } partialFix = null; partialFixSentenceType = NMEASentenceType.Unknown; } else if (fixSource == NMEASentenceType.GGA) { // Don't have speed information, so calculate it. m_MostRecentGPSFix = fix; CalculateSpeedAndHeading(m_MostRecentGPSFix, false); } else if (fixSource == NMEASentenceType.RMC) { // Publish the fix as is. m_MostRecentGPSFix = fix; } } else { // Save the fix until we hit the trigger sentence. partialFix = fix; partialFixSentenceType = fixSource; } }
public void Reset() { readBuffer = ""; partialFix = null; partialFixSentenceType = NMEASentenceType.Unknown; haveGGA = false; haveRMC = false; lastGGATimestamp = new DateTime(0); lastRMCTimestamp = new DateTime(0); fixTriggerSentence = NMEASentenceType.Unknown; savedFix = null; m_MostRecentGPSFix = null; gsaData = null; partialSatelliteVehicles = null; partialSatelliteVehicleIndex = 0; m_MostRecentSatelliteVehicles = null; lastGSVMessageNumber = 0; }
public void ProcessReceivedData(byte[] rawData) { const string hexChars = "0123456789ABCDEF"; // Add the data to the read buffer. Encoding ascii = Encoding.ASCII; readBuffer += ascii.GetString(rawData, 0, rawData.Length).ToUpper(); // Process received lines. The last entry in the array (which may be an empty string) // is always an incomplete line as it wasn't followed by a "\n". Therefore it needs // to go back into the read buffer. string[] lines = readBuffer.Split(new char[] {'\n'}); readBuffer = lines[lines.Length - 1]; int i; for (i = 0; i < lines.Length - 1; i++) { // Split the checksum off from the line. If we don't find one, ignore the line. int hi, lo; string[] elements = lines[i].Trim().Split(new char[] {'*'}); if ((elements.Length == 2) && elements[0].StartsWith("$") && (elements[1].Length == 2) && ((hi = hexChars.IndexOf(elements[1][0])) >= 0) && ((lo = hexChars.IndexOf(elements[1][1])) >= 0)) { // Verify the checksum. byte checksum = (byte)(hi << 4 | lo); byte c = 0; int j; for (j = 1; j < elements[0].Length; j++) c ^= (byte)elements[0][j]; if (c == checksum) { // Valid NMEA sentence. Split it into its components and process it after // removing the leading '$'. There will always be at least one part, even // if it is empty. string[] parts = elements[0].Remove(0, 1).Split(new char[] {','}); // Decide whether to use GGA or RMC sentences, or both. if (fixTriggerSentence == NMEASentenceType.Unknown) { if (parts[0] == "GPGGA") { haveGGA = true; if (! haveRMC && (lastGGATimestamp.Ticks != 0)) { // This is the second GGA fix we have seen without an intervening RMC fix. // Assume no RMC packets. fixTriggerSentence = NMEASentenceType.GGA; } lastGGATimestamp = ParseNMEATimestamp(parts.Length > 0 ? parts[1] : ""); if (haveRMC) { if (lastRMCTimestamp == lastGGATimestamp) fixTriggerSentence = NMEASentenceType.GGA; else fixTriggerSentence = NMEASentenceType.RMC; } } else if (parts[0] == "GPRMC") { haveRMC = true; if (! haveGGA && (lastRMCTimestamp.Ticks != 0)) { // This is the second RMC fix we have seen without an intervening GGA fix. // Assume no GGA packets. fixTriggerSentence = NMEASentenceType.RMC; } lastRMCTimestamp = ParseNMEATimestamp(parts.Length > 0 ? parts[1] : ""); if (haveGGA) { if (lastGGATimestamp == lastRMCTimestamp) fixTriggerSentence = NMEASentenceType.RMC; else fixTriggerSentence = NMEASentenceType.GGA; } } } // Process specific sentence types. switch (parts[0]) { case "GPGGA": ProcessGGA(parts); break; case "GPGSA": ProcessGSA(parts); break; case "GPGSV": ProcessGSV(parts); break; case "GPRMC": ProcessRMC(parts); break; } } } } }
public void ProcessReceivedData(byte[] rawData) { const string hexChars = "0123456789ABCDEF"; // Add the data to the read buffer. Encoding ascii = Encoding.ASCII; readBuffer += ascii.GetString(rawData, 0, rawData.Length).ToUpper(); // Process received lines. The last entry in the array (which may be an empty string) // is always an incomplete line as it wasn't followed by a "\n". Therefore it needs // to go back into the read buffer. string[] lines = readBuffer.Split(new char[] { '\n' }); readBuffer = lines[lines.Length - 1]; int i; for (i = 0; i < lines.Length - 1; i++) { // Split the checksum off from the line. If we don't find one, ignore the line. int hi, lo; string[] elements = lines[i].Trim().Split(new char[] { '*' }); if ((elements.Length == 2) && elements[0].StartsWith("$") && (elements[1].Length == 2) && ((hi = hexChars.IndexOf(elements[1][0])) >= 0) && ((lo = hexChars.IndexOf(elements[1][1])) >= 0)) { // Verify the checksum. byte checksum = (byte)(hi << 4 | lo); byte c = 0; int j; for (j = 1; j < elements[0].Length; j++) { c ^= (byte)elements[0][j]; } if (c == checksum) { // Valid NMEA sentence. Split it into its components and process it after // removing the leading '$'. There will always be at least one part, even // if it is empty. string[] parts = elements[0].Remove(0, 1).Split(new char[] { ',' }); // Decide whether to use GGA or RMC sentences, or both. if (fixTriggerSentence == NMEASentenceType.Unknown) { if (parts[0] == "GPGGA") { haveGGA = true; if (!haveRMC && (lastGGATimestamp.Ticks != 0)) { // This is the second GGA fix we have seen without an intervening RMC fix. // Assume no RMC packets. fixTriggerSentence = NMEASentenceType.GGA; } lastGGATimestamp = ParseNMEATimestamp(parts.Length > 0 ? parts[1] : ""); if (haveRMC) { if (lastRMCTimestamp == lastGGATimestamp) { fixTriggerSentence = NMEASentenceType.GGA; } else { fixTriggerSentence = NMEASentenceType.RMC; } } } else if (parts[0] == "GPRMC") { haveRMC = true; if (!haveGGA && (lastRMCTimestamp.Ticks != 0)) { // This is the second RMC fix we have seen without an intervening GGA fix. // Assume no GGA packets. fixTriggerSentence = NMEASentenceType.RMC; } lastRMCTimestamp = ParseNMEATimestamp(parts.Length > 0 ? parts[1] : ""); if (haveGGA) { if (lastGGATimestamp == lastRMCTimestamp) { fixTriggerSentence = NMEASentenceType.RMC; } else { fixTriggerSentence = NMEASentenceType.GGA; } } } } // Process specific sentence types. switch (parts[0]) { case "GPGGA": ProcessGGA(parts); break; case "GPGSA": ProcessGSA(parts); break; case "GPGSV": ProcessGSV(parts); break; case "GPRMC": ProcessRMC(parts); break; } } } } }